天天看點

SpringCloud(四)Ribbon自定義負載均衡

上篇文章我們已經完成了Ribbon負載均衡的功能。做法很簡單,隻需要在RestTemplate添加@LoanBalanced 的注解。預設情況下,Ribbon的負載均衡政策是RoundRobbin(輪訓)的方式,可很多時候在特定場景下需要不同的政策,這個時候就需要自定義Ribbon政策了。看下面代碼:

[java]  view plain  copy

  1. package com.zhuyang.cloud.controller;  
  2. import org.springframework.beans.factory.annotation.Autowired;  
  3. import org.springframework.cloud.client.loadbalancer.LoadBalanced;  
  4. import org.springframework.cloud.netflix.ribbon.RibbonClient;  
  5. import org.springframework.context.annotation.Bean;  
  6. import org.springframework.web.bind.annotation.PathVariable;  
  7. import org.springframework.web.bind.annotation.RequestMapping;  
  8. import org.springframework.web.bind.annotation.RequestMethod;  
  9. import org.springframework.web.bind.annotation.RestController;  
  10. import org.springframework.web.client.RestTemplate;  
  11. import com.zhuyang.cloud.entity.User;  
  12. import com.zhuyang.config.RibbonConfiguration;  
  13. @RestController  
  14. @RibbonClient(name = "microservice-provider", configuration = RibbonConfiguration.class)//name是provider的服務名  <span style="font-family: Arial, Helvetica, sans-serif;">RibbonConfiguration為自定義配置</span>  
  15. public class MovieController {  
  16.     @Bean  
  17.     @LoadBalanced  
  18.     public RestTemplate restTemplate() { // equals to RestTemplate  
  19.         // restTemplate=new RestTemplate();  
  20.         return new RestTemplate();  
  21.     }  
  22.     @Autowired  
  23.     private RestTemplate restTemplate;  
  24.     @RequestMapping(value = "/movie/{id}", method = RequestMethod.GET)  
  25.     public User findById(@PathVariable Long id) {  
  26.         // return restTemplate.getForEntity("http://localhost:8000/service/"+id,  
  27.         // User.class).getBody();  
  28.         return restTemplate.getForEntity("http://microservice-provider/provider/service/" + id, User.class).getBody();  
  29.     }  
  30. }  

[html]  view plain  copy

  1. server:   
  2.   port: 8001   
  3. eureka:   
  4.   client:   
  5.     serviceUrl:   
  6.       defaultZone: http://user:[email protected]:8761/eureka/    # 指定注冊中心的位址   
  7.   instance:   
  8.     preferIpAddress: true   
  9. spring:   
  10.   application:   
  11.     name: microservice-consumer   
  12. microservice-provider:  ##config ribbon   
  13.   ribbon:   
  14.     eureka:   
  15.       enabled: false   
  16.     listOfServers: localhost:8000, localhost:8002,localhost:8003 ##假設provider有3台instance端口分别是8000 8002 8003  
  17.     ServerListRefreshInterval: 15000  

[java]  view plain  copy

  1. package com.zhuyang.config;  
  2. import org.springframework.beans.factory.annotation.Autowired;  
  3. import org.springframework.context.annotation.Bean;  
  4. import com.netflix.client.config.IClientConfig;  
  5. import com.netflix.loadbalancer.IPing;  
  6. import com.netflix.loadbalancer.IRule;  
  7. import com.netflix.loadbalancer.PingUrl;  
  8. import com.netflix.loadbalancer.ZoneAvoidanceRule;  
  9. public class RibbonConfiguration {  
  10.     @Autowired  
  11.     private IClientConfig ribbonClientConfig;  
  12.     @Bean  
  13.     public IPing ribbonPing(IClientConfig config) {  
  14.         // ping url will try to access http://microservice-provider/provider/ to  
  15.         // see if reponse code is 200 . check PingUrl.isAlive()  
  16.         // param /provider/ is the context-path of provider service  
  17.         return new PingUrl(false, "/provider/");  
  18.     }  
  19.     @Bean  
  20.     public IRule ribbonRule(IClientConfig config) {  
  21.         // return new AvailabilityFilteringRule();  
  22.          return new RandomRule();//  
  23.         // return new BestAvailableRule();  
  24.         // return new RoundRobinRule();//輪詢  
  25.         // return new WeightedResponseTimeRule();  
  26.         // return new RetryRule();  
  27.         // return new ZoneAvoidanceRule();  
  28.     }  
  29. }  

在RibbonConfiguration中的ribbonRule方法就是用來定義不用的政策,每種政策所對應的實作類和描述 都已經添加了注釋。例如我們傳回的是RandomRule政策,那麼我們在多次請求provider的時候就不再是輪訓的方式進行命中,而是随機方式。。下面是RandomRule的代碼實作

[java]  view plain  copy

  1. public Server choose(ILoadBalancer lb, Object key) {  
  2.         if (lb == null) {  
  3.             return null;  
  4.         }  
  5.         Server server = null;  
  6.         while (server == null) {  
  7.             if (Thread.interrupted()) {  
  8.                 return null;  
  9.             }  
  10.             List<Server> upList = lb.getReachableServers();//get all reachable server .list  listOfServers: localhost:8000, localhost:8002,localhost:8003  
  11.             List<Server> allList = lb.getAllServers();  
  12.             int serverCount = allList.size();  
  13.             if (serverCount == 0) {  
  14.                 return null;  
  15.             }  
  16.             int index = rand.nextInt(serverCount);//get random index  
  17.             server = upList.get(index);//get specified server eg:<span style="font-family: Arial, Helvetica, sans-serif;">localhost:8000</span>  
  18.             if (server == null) {  
  19.                 Thread.yield();  
  20.                 continue;  
  21.             }  
  22.             if (server.isAlive()) {  
  23.                 return (server);  
  24.             }  
  25.             // Shouldn't actually happen.. but must be transient or a bug.  
  26.             server = null;  
  27.             Thread.yield();  
  28.         }  
  29.         return server;//return selected server  
  30.     }  

繼續閱讀