SpringCloud(四)Ribbon自定义负载均衡

上篇文章我们已经完成了Ribbon负载均衡的功能。做法很简单,只需要在RestTemplate添加@LoanBalanced 的注解。默认情况下,Ribbon的负载均衡策略是RoundRobbin(轮训)的方式,可很多时候在特定场景下需要不同的策略,这个时候就需要自定义Ribbon策略了。看下面代码:

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

[html]  view plain  copy
  1. server:   
  2.   port: 8001   
  3. eureka:   
  4.   client:   
  5.     serviceUrl:   
  6.       defaultZone: http://user:password123@localhost: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.   
  3. import org.springframework.beans.factory.annotation.Autowired;  
  4. import org.springframework.context.annotation.Bean;  
  5.   
  6. import com.netflix.client.config.IClientConfig;  
  7. import com.netflix.loadbalancer.IPing;  
  8. import com.netflix.loadbalancer.IRule;  
  9. import com.netflix.loadbalancer.PingUrl;  
  10. import com.netflix.loadbalancer.ZoneAvoidanceRule;  
  11.   
  12. /** 
  13.  *  
  14.  * Here, we override the IPing and IRule used by the default load balancer. The 
  15.  * default IPing is a NoOpPing (which doesn’t actually ping server instances, 
  16.  * instead always reporting that they’re stable), and the default IRule is a 
  17.  * ZoneAvoidanceRule (which avoids the Amazon EC2 zone that has the most 
  18.  * malfunctioning servers, and might thus be a bit difficult to try out in our 
  19.  * local environment). 
  20.  *  
  21.  */  
  22. public class RibbonConfiguration {  
  23.     @Autowired  
  24.     private IClientConfig ribbonClientConfig;  
  25.   
  26.     /** 
  27.      * Our IPing is a PingUrl, which will ping a URL to check the status of each 
  28.      * server.provider has, as you’ll recall, a method mapped to the / path; 
  29.      * that means that Ribbon will get an HTTP 200 response when it pings a 
  30.      * running provider server. 
  31.      *  
  32.      * server list defined in application.yml :listOfServers: localhost:8000, 
  33.      * localhost:8002,localhost:8003 
  34.      *  
  35.      */  
  36.     @Bean  
  37.     public IPing ribbonPing(IClientConfig config) {  
  38.         // ping url will try to access http://microservice-provider/provider/ to  
  39.         // see if reponse code is 200 . check PingUrl.isAlive()  
  40.         // param /provider/ is the context-path of provider service  
  41.         return new PingUrl(false"/provider/");  
  42.     }  
  43.   
  44.     /** 
  45.      * The IRule we set up, the AvailabilityFilteringRule, will use Ribbon’s 
  46.      * built-in circuit breaker functionality to filter out any servers in an 
  47.      * “open-circuit” state: if a ping fails to connect to a given server, or if 
  48.      * it gets a read failure for the server, Ribbon will consider that server 
  49.      * “dead” until it begins to respond normally. 
  50.      *  
  51.      * AvailabilityFilteringRule | 过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值) | 使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态 
  52.      * RandomRule  | 随机选择一个server 
  53.      * BestAvailabl eRule | 选择一个最小的并发请求的server | 逐个考察Server,如果Server被tripped了,则忽略,在选择其中 
  54.      * RoundRobinRule  |  roundRobin方式轮询选择  |  轮询index,选择index对应位置的server 
  55.      * WeightedResponseTimeRule  |  根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。  |  一 个后台线程定期的从status里面读取评价响应时间,为每个server计算一个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权重。当刚开始运行,没有形成statas时,使用roubine策略选择 server。 
  56.      * RetryRule  |  对选定的负载均衡策略机上重试机制。 |  在一个配置时间段内当选择server不成功,则一直尝试使用subRule的方式选择一个可用的server 
  57.      * ZoneAvoidanceRule  |  复合判断server所在区域的性能和server的可用性选择server  |  使 用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个 zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的 Server。 
  58.      * @param config 
  59.      * @return 
  60.      */  
  61.     @Bean  
  62.     public IRule ribbonRule(IClientConfig config) {  
  63.         // return new AvailabilityFilteringRule();  
  64.          return new RandomRule();//  
  65.         // return new BestAvailableRule();  
  66.         // return new RoundRobinRule();//轮询  
  67.         // return new WeightedResponseTimeRule();  
  68.         // return new RetryRule();  
  69.         // return new ZoneAvoidanceRule();  
  70.     }  
  71. }  

在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.   
  7.         while (server == null) {  
  8.             if (Thread.interrupted()) {  
  9.                 return null;  
  10.             }  
  11.             List<Server> upList = lb.getReachableServers();//get all reachable server .list  listOfServers: localhost:8000, localhost:8002,localhost:8003  
  12.             List<Server> allList = lb.getAllServers();  
  13.   
  14.             int serverCount = allList.size();  
  15.             if (serverCount == 0) {  
  16.                 /* 
  17.                  * No servers. End regardless of pass, because subsequent passes 
  18.                  * only get more restrictive. 
  19.                  */  
  20.                 return null;  
  21.             }  
  22.   
  23.             int index = rand.nextInt(serverCount);//get random index  
  24.             server = upList.get(index);//get specified server eg:<span style="font-family: Arial, Helvetica, sans-serif;">localhost:8000</span>  
  25.   
  26.             if (server == null) {  
  27.                 /* 
  28.                  * The only time this should happen is if the server list were 
  29.                  * somehow trimmed. This is a transient condition. Retry after 
  30.                  * yielding. 
  31.                  */  
  32.                 Thread.yield();  
  33.                 continue;  
  34.             }  
  35.   
  36.             if (server.isAlive()) {  
  37.                 return (server);  
  38.             }  
  39.   
  40.             // Shouldn't actually happen.. but must be transient or a bug.  
  41.             server = null;  
  42.             Thread.yield();  
  43.         }  
  44.   
  45.         return server;//return selected server  
  46.   
  47.     }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值