SpringCloud(四)Ribbon自定义负载均衡
  AJDqNpVvznez 2023年11月02日 90 0


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




    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. }


    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



    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的代码实现



    1. public Server choose(ILoadBalancer lb, Object key) {  
    2. if (lb == null) {
    3. return null;
    4. }
    5. null;
    6.
    7. while (server == null) {
    8. if (Thread.interrupted()) {
    9. return null;
    10. }
    11. //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. //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. null;
    42. Thread.yield();
    43. }
    44.
    45. return server;//return selected server
    46.
    47. }
    48.
    【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

    上一篇: RFC3550 RTP 中文版 下一篇: 三丰云服务器
    1. 分享:
    最后一次编辑于 2023年11月08日 0

    暂无评论

    推荐阅读
      Fo7woytj0C0D   2023年12月23日   31   0   0 pythonsedidepythonidesed
    AJDqNpVvznez