IRule

IRule

AbstractloadBalancerRule

负载均衡策略抽象类 负责获得负载均衡器 保存在内部 通过负载均衡器维护的信息 作为分配的依据

  1. public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
  2.  
  3. private ILoadBalancer lb;
  4.  
  5. @Override
  6. public void setLoadBalancer(ILoadBalancer lb){
  7. this.lb = lb;
  8. }
  9.  
  10. @Override
  11. public ILoadBalancer getLoadBalancer(){
  12. return lb;
  13. }
  14. }

RandomRule

随机选择一个服务的策略

  1. public class RandomRule extends AbstractLoadBalancerRule {
  2.  
  3. @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
  4. public Server choose(ILoadBalancer lb, Object key) {
  5. if (lb == null) {
  6. return null;
  7. }
  8. Server server = null;
  9.  
  10. while (server == null) {
  11. if (Thread.interrupted()) {
  12. return null;
  13. }
  14. //通过负载均衡器获得可用服务
  15. List<Server> upList = lb.getReachableServers();
  16. //通过负载均衡器获得所有服务
  17. List<Server> allList = lb.getAllServers();
  18.  
  19. int serverCount = allList.size();
  20. //没有服务返回空
  21. if (serverCount == 0) {
  22. /*
  23. * No servers. End regardless of pass, because subsequent passes
  24. * only get more restrictive.
  25. */
  26. return null;
  27. }
  28. //通过ThreadLocalRandom.current().nextInt(serverCount); 获得一个随机数
  29. int index = chooseRandomInt(serverCount);
  30. //获得一个随机的服务
  31. server = upList.get(index);
  32.  
  33. if (server == null) {
  34. /**
  35. * 线程让步 将线程的cpu执行时间让步出来 可以理解为本来是排队有序的做一件事情
  36. * 然后轮到那个人的时候他突然说 大家一起竞赛吧 谁先抢到就是谁的 也包括自己 线程优先级越高 获得的机率越大
  37. */
  38. Thread.yield();
  39. continue;
  40. }
  41. //判断服务是否有效
  42. if (server.isAlive()) {
  43. return (server);
  44. }
  45.  
  46. // Shouldn't actually happen.. but must be transient or a bug.
  47. server = null;
  48. Thread.yield();
  49. }
  50.  
  51. return server;
  52.  
  53. }

RoundRobinRule

  1. public class RoundRobinRule extends AbstractLoadBalancerRule {
  2.  
  3. private AtomicInteger nextServerCyclicCounter;
  4. public Server choose(ILoadBalancer lb, Object key) {
  5. if (lb == null) {
  6. log.warn("no load balancer");
  7. return null;
  8. }
  9.  
  10. Server server = null;
  11. int count = 0;
  12. while (server == null && count++ < 10) {
  13. //获得所有有效服务
  14. List<Server> reachableServers = lb.getReachableServers();
  15. //获得所有服务
  16. List<Server> allServers = lb.getAllServers();
  17. int upCount = reachableServers.size();
  18. int serverCount = allServers.size();
  19.  
  20. if ((upCount == 0) || (serverCount == 0)) {
  21. log.warn("No up servers available from load balancer: " + lb);
  22. return null;
  23. }
  24.  
  25. //获得线性轮训 当前轮到的服务下标
  26. int nextServerIndex = incrementAndGetModulo(serverCount);
  27. //去除服务
  28. server = allServers.get(nextServerIndex);
  29.  
  30. if (server == null) {
  31. //让出cpu执行时间
  32. Thread.yield();
  33. continue;
  34. }
  35.  
  36. if (server.isAlive() && (server.isReadyToServe())) {
  37. return (server);
  38. }
  39.  
  40. // Next.
  41. server = null;
  42. }
  43.  
  44. if (count >= 10) {
  45. log.warn("No available alive servers after 10 tries from load balancer: "
  46. + lb);
  47. }
  48. return server;
  49. }
  50. private int incrementAndGetModulo(int modulo) {
  51. //死循环
  52. for (;;) {
  53. //cas AtomicInteger 类 保证++的原子性
  54. int current = nextServerCyclicCounter.get();
  55. //线性轮训算法
  56. int next = (current + 1) % modulo;
  57. //compareAndSet的作用是防止多线程下还没执行到这一句 current被修改 如果被修改返回false 重新开始
  58. if (nextServerCyclicCounter.compareAndSet(current, next))
  59. return next;
  60. }
  61. }

RetryRule

  1. /**
  2. * 具有重试机制的Rule
  3. */
  4. public class RetryRule extends AbstractLoadBalancerRule {
  5. //内部默认维护一个线性轮训的Rule
  6. IRule subRule = new RoundRobinRule();
  7. long maxRetryMillis = 500;
  8.  
  9. public RetryRule(IRule subRule) {
  10. this.subRule = (subRule != null) ? subRule : new RoundRobinRule();
  11. }
  12.  
  13. public RetryRule(IRule subRule, long maxRetryMillis) {
  14. this.subRule = (subRule != null) ? subRule : new RoundRobinRule();
  15. this.maxRetryMillis = (maxRetryMillis > 0) ? maxRetryMillis : 500;
  16. }
  17. public IRule getRule() {
  18. return subRule;
  19. }
  20.  
  21. /**
  22. * 内部找到就返回 找不到就重试
  23. * @param lb
  24. * @param key
  25. * @return
  26. */
  27. public Server choose(ILoadBalancer lb, Object key) {
  28. long requestTime = System.currentTimeMillis();
  29. //尝试结束时间 maxRetryMillis阈值 可配置
  30. long deadline = requestTime + maxRetryMillis;
  31.  
  32. Server answer = null;
  33.  
  34. answer = subRule.choose(key);
  35.  
  36. if (((answer == null) || (!answer.isAlive()))
  37. && (System.currentTimeMillis() < deadline)) {
  38.  
  39. InterruptTask task = new InterruptTask(deadline
  40. - System.currentTimeMillis());
  41. /**
  42. * new Tread().interrupt()给线程增加一个中断标志 但是并不会影响线程执行 但是如果这个时候对线程执行sleep和 wait 底层会将中断状态重置为false并抛出异常InterruptedException 所以我们可以根据捕获这个异常判断线程是否中断
  43. * Thread.interrupted()判断线程的中断状态 并重置线程的中断状态为false
  44. * new Tread().isInterrupted();仅仅判断线程是否中断不会重置
  45. */
  46.  
  47. while (!Thread.interrupted()) {
  48. answer = subRule.choose(key);
  49.  
  50. if (((answer == null) || (!answer.isAlive()))
  51. && (System.currentTimeMillis() < deadline)) {
  52. /* pause and retry hoping it's transient */
  53. Thread.yield();
  54. } else {
  55. break;
  56. }
  57. }
  58.  
  59. task.cancel();
  60. }
  61.  
  62. if ((answer == null) || (!answer.isAlive())) {
  63. return null;
  64. } else {
  65. return answer;
  66. }
  67. }
  1. /**
  2. * RoundRobinRule的扩展
  3. * 内部根据实例运行情况来进行权重 并根据权重挑选实例
  4. */
  5. public class WeightedResponseTimeRule extends RoundRobinRule {
  6.  
  7. void initialize(ILoadBalancer lb) {
  8. if (this.serverWeightTimer != null) {
  9. this.serverWeightTimer.cancel();
  10. }
  11.  
  12. this.serverWeightTimer = new Timer("NFLoadBalancer-serverWeightTimer-" + this.name, true);
  13. //开启一个定时任务为实例进行统计 用于计算权重 默认30秒执行一次
  14. this.serverWeightTimer.schedule(new WeightedResponseTimeRule.DynamicServerWeightTask(), 0L, (long)this.serverWeightTaskTimerInterval);
  15. WeightedResponseTimeRule.ServerWeight sw = new WeightedResponseTimeRule.ServerWeight();
  16. sw.maintainWeights();
  17. Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
  18. public void run() {
  19. WeightedResponseTimeRule.logger.info("Stopping NFLoadBalancer-serverWeightTimer-" + WeightedResponseTimeRule.this.name);
  20. WeightedResponseTimeRule.this.serverWeightTimer.cancel();
  21. }
  22. }));
  23. }
  24.  
  25. @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
  26. public Server choose(ILoadBalancer lb, Object key) {
  27. if (lb == null) {
  28. return null;
  29. } else {
  30. Server server = null;
  31.  
  32. while(server == null) {
  33. //获得权重
  34. List<Double> currentWeights = this.accumulatedWeights;
  35. if (Thread.interrupted()) {
  36. return null;
  37. }
  38. //获得所有服务
  39. List<Server> allList = lb.getAllServers();
  40. int serverCount = allList.size();
  41. if (serverCount == 0) {
  42. return null;
  43. }
  44.  
  45. int serverIndex = 0;
  46. //获得最后一个权重
  47. double maxTotalWeight = currentWeights.size() == 0 ? 0.0D : (Double)currentWeights.get(currentWeights.size() - 1);
  48.  
  49. //如果权重大于0.01
  50. if (maxTotalWeight >= 0.001D && serverCount == currentWeights.size()) {
  51. //通过随机数计算一个权重
  52. double randomWeight = this.random.nextDouble() * maxTotalWeight;
  53. int n = 0;
  54.  
  55. for(Iterator var13 = currentWeights.iterator(); var13.hasNext(); ++n) {
  56. Double d = (Double)var13.next();
  57. //如果实例在那个权重区间 则定位此服务索引
  58. if (d >= randomWeight) {
  59. serverIndex = n;
  60. break;
  61. }
  62. }
  63. //返回对应实例
  64. server = (Server)allList.get(serverIndex);
  65. } else {
  66. //如果实例的权重小于0.0.1 则采用父类的线性轮训算法
  67. server = super.choose(this.getLoadBalancer(), key);
  68. if (server == null) {
  69. return server;
  70. }
  71. }
  72.  
  73. if (server == null) {
  74. Thread.yield();
  75. } else {
  76. if (server.isAlive()) {
  77. return server;
  78. }
  79.  
  80. server = null;
  81. }
  82. }
  83.  
  84. return server;
  85. }
  86. }
  87.  
  88. void setWeights(List<Double> weights) {
  89. this.accumulatedWeights = weights;
  90. }
  91.  
  92. public void initWithNiwsConfig(IClientConfig clientConfig) {
  93. super.initWithNiwsConfig(clientConfig);
  94. this.serverWeightTaskTimerInterval = (Integer)clientConfig.get(WEIGHT_TASK_TIMER_INTERVAL_CONFIG_KEY, 30000);
  95. }
  96.  
  97. class ServerWeight {
  98. ServerWeight() {
  99. }
  100.  
  101. public void maintainWeights() {
  102. ILoadBalancer lb = WeightedResponseTimeRule.this.getLoadBalancer();
  103. if (lb != null) {
  104. if (WeightedResponseTimeRule.this.serverWeightAssignmentInProgress.compareAndSet(false, true)) {
  105. try {
  106. WeightedResponseTimeRule.logger.info("Weight adjusting job started");
  107. AbstractLoadBalancer nlb = (AbstractLoadBalancer)lb;
  108. //获得统计信息
  109. LoadBalancerStats stats = nlb.getLoadBalancerStats();
  110. if (stats != null) {
  111. //保存所有实例的的平均响应时间总和
  112. double totalResponseTime = 0.0D;
  113.  
  114. ServerStats ss;
  115. for(Iterator var6 = nlb.getAllServers().iterator(); var6.hasNext(); totalResponseTime += ss.getResponseTimeAvg()) {
  116. Server server = (Server)var6.next();
  117. ss = stats.getSingleServerStat(server);
  118. }
  119.  
  120. Double weightSoFar = 0.0D;
  121. //用于保存权重 下标对应实例在负载均衡器中的位置
  122. List<Double> finalWeights = new ArrayList();
  123. Iterator var20 = nlb.getAllServers().iterator();
  124.  
  125. while(var20.hasNext()) {
  126. Server serverx = (Server)var20.next();
  127. //如果服务的状态不再快照汇总 则这里加载
  128. ServerStats ssx = stats.getSingleServerStat(serverx);
  129. //计算权重 平均响应时间总和-实例的响应平均响应时间+weightSoFar
  130. double weight = totalResponseTime - ssx.getResponseTimeAvg();
  131. //每次都会累加
  132. weightSoFar = weightSoFar + weight;
  133. //保存权重
  134. finalWeights.add(weightSoFar);
  135. }
  136.  
  137. WeightedResponseTimeRule.this.setWeights(finalWeights);
  138. return;
  139. }
  140. } catch (Exception var16) {
  141. WeightedResponseTimeRule.logger.error("Error calculating server weights", var16);
  142. return;
  143. } finally {
  144. WeightedResponseTimeRule.this.serverWeightAssignmentInProgress.set(false);
  145. }
  146.  
  147. }
  148. }
  149. }
  150. }
  151. //负责权重计算的定时任务
  152. class DynamicServerWeightTask extends TimerTask {
  153. DynamicServerWeightTask() {
  154. }
  155.  
  156. public void run() {
  157. WeightedResponseTimeRule.ServerWeight serverWeight = WeightedResponseTimeRule.this.new ServerWeight();
  158.  
  159. try {
  160. //计算权重
  161. serverWeight.maintainWeights();
  162. } catch (Exception var3) {
  163. WeightedResponseTimeRule.logger.error("Error running DynamicServerWeightTask for {}", WeightedResponseTimeRule.this.name, var3);
  164. }
  165.  
  166. }
  167. }
  168. }

WeightedResponseTimeRule

ClientConfigEnabledRoundRobinRule

不怎么使用 也是线性轮训  用于继承扩展

  1. public class ClientConfigEnabledRoundRobinRule extends AbstractLoadBalancerRule {
  2.  
  3. RoundRobinRule roundRobinRule = new RoundRobinRule();
  4.  
  5. @Override
  6. public void initWithNiwsConfig(IClientConfig clientConfig) {
  7. roundRobinRule = new RoundRobinRule();
  8. }
  9.  
  10. @Override
  11. public void setLoadBalancer(ILoadBalancer lb) {
  12. super.setLoadBalancer(lb);
  13. roundRobinRule.setLoadBalancer(lb);
  14. }
  15.  
  16. @Override
  17. public Server choose(Object key) {
  18. if (roundRobinRule != null) {
  19. return roundRobinRule.choose(key);
  20. } else {
  21. throw new IllegalArgumentException(
  22. "This class has not been initialized with the RoundRobinRule class");
  23. }
  24. }
  25.  
  26. }

BestAvailableRule

选出最空闲的服务实例

  1. /**
  2. *该策略是选择 最空闲的那一个
  3. */
  4. public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule {
  5.  
  6. private LoadBalancerStats loadBalancerStats;
  7.  
  8. @Override
  9. public Server choose(Object key) {
  10. if (loadBalancerStats == null) {
  11. return super.choose(key);
  12. }
  13. //取得所有服务实例
  14. List<Server> serverList = getLoadBalancer().getAllServers();
  15. int minimalConcurrentConnections = Integer.MAX_VALUE;
  16. long currentTime = System.currentTimeMillis();
  17. Server chosen = null;
  18. //遍历所有服务实例
  19. for (Server server: serverList) {
  20. ServerStats serverStats = loadBalancerStats.getSingleServerStat(server);
  21. if (!serverStats.isCircuitBreakerTripped(currentTime)) {
  22. int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);
  23. //取得最空闲的服务
  24. if (concurrentConnections < minimalConcurrentConnections) {
  25. minimalConcurrentConnections = concurrentConnections;
  26. chosen = server;
  27. }
  28. }
  29. }
  30. //如果没有找到 继续延用父类的线性轮训
  31. if (chosen == null) {
  32. return super.choose(key);
  33. } else {
  34. return chosen;
  35. }
  36. }
  37.  
  38. }

PredicateBasedRule

先过滤清单再轮训

  1. public abstract class PredicateBasedRule extends ClientConfigEnabledRoundRobinRule {
  2. //内部使用PredicateBasedRule 实现服务的过滤
  3. public abstract AbstractServerPredicate getPredicate();
  4.  
  5. @Override
  6. public Server choose(Object key) {
  7. ILoadBalancer lb = getLoadBalancer();
  8. /**
  9. * 基于Predicate实现服务的过滤
  10. * Predicate是Google Guava Collection的集合工具
  11. * 可以帮助我们让集合操作代码更为简短精练并大大增强代码的可读 性
  12. */
  13. Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
  14. if (server.isPresent()) {
  15. return server.get();
  16. } else {
  17. return null;
  18. }
  19. }
  20. }
  1. public abstract class AbstractServerPredicate implements Predicate<PredicateKey> {
  2. public List<Server> getEligibleServers(List<Server> servers, Object loadBalancerKey) {
  3. if (loadBalancerKey == null) {
  4. return ImmutableList.copyOf(Iterables.filter(servers, this.getServerOnlyPredicate()));
  5. } else {
  6. List<Server> results = Lists.newArrayList();
  7. for (Server server : servers) {
  8. //过滤服务
  9. if (this.apply(new PredicateKey(loadBalancerKey, server))) {
  10. results.add(server);
  11. }
  12. }
  13. return results;
  14. }
  15. }
  16.  
  17. public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers) {
  18. List<Server> eligible = getEligibleServers(servers);
  19. if (eligible.size() == 0) {
  20. return Optional.absent();
  21. }
  22. return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
  23. }
  24.  
  25. }

AvailabilityFilteringRule

  1. public class AvailabilityFilteringRule extends PredicateBasedRule {
  2. private AbstractServerPredicate predicate;
  3. public AvailabilityFilteringRule() {
  4. super();
  5. //初始化 下面predicate.apply的比较策略
  6. predicate = CompositePredicate.withPredicate(new AvailabilityPredicate(this, null))
  7. .addFallbackPredicate(AbstractServerPredicate.alwaysTrue())
  8. .build();
  9. }
  10. @Override
  11. public void initWithNiwsConfig(IClientConfig clientConfig) {
  12. //初始化下面 predicate.apply的比较策略
  13. predicate = CompositePredicate.withPredicate(new AvailabilityPredicate(this, clientConfig))
  14. .addFallbackPredicate(AbstractServerPredicate.alwaysTrue())
  15. .build();
  16. }
  17. @Override
  18. public Server choose(Object key) {
  19. int count = 0;
  20. Server server = roundRobinRule.choose(key);
  21. while (count++ <= 10) {
  22. /**
  23. * 优化父类 先过滤再遍历的额外开销
  24. * 一边遍历 判断是否故障或者超过最大并发阀值 是否故障, 即断路器是否生效已断开。
  25. * 实例的并发请求数大于阙值,默认值为 232 -1, 该配置可通过参数<clientName>. <nameSpace>.ActiveConnectionsLimit 来修改。
  26. */
  27. if (predicate.apply(new PredicateKey(server))) {
  28. return server;
  29. }
  30. server = roundRobinRule.choose(key);
  31. }
  32. return super.choose(key);
  33. }
  34.  
  35. @Override
  36. public AbstractServerPredicate getPredicate() {
  37. return predicate;
  38. }
  39. }

Spring Cloud-Ribbon负载均衡策略类IRule(五)的更多相关文章

  1. Spring Cloud Ribbon负载均衡配置类放在Spring boot主类同级增加Exclude过滤后报Field config in com.cloud.web.controller.RibbonConfiguration required a bean of type 'com.netflix.client.config.IClientConfig' that could not b

    环境: Spring Cloud:Finchley.M8 Spring Boot:2.0.0.RELEASE 目录结构: 可以看到代码第13行的注释,我已经在@ComponentScan注解中添加了E ...

  2. SpringCloud微服务实战二:Spring Cloud Ribbon 负载均衡 + Spring Cloud Feign 声明式调用

    1.Spring Cloud Ribbon的作用 Ribbon是Netflix开发的一个负载均衡组件,它在服务体系中起着重要作用,Pivotal将其整合成为Spring Cloud Ribbon,与其 ...

  3. Spring Cloud Ribbon负载均衡

    目录 一.简介 二.客户端负载均衡 三.RestTemplate详解 GET请求 POST请求 PUT请求 DELETE请求 一.简介 ​ Spring Cloud Ribbon是一个基于HTTP 和 ...

  4. Spring Cloud Ribbon负载均衡(快速搭建)

    Spring Cloud Ribbon 是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现.通过 Spring Cloud 的封装, 可以让我们轻松地将面向服务的 ...

  5. springcloud(十四)、ribbon负载均衡策略应用案例

    一.eureka-server服务中心项目不再创建 二.eureka-common-empdept公共组件项目不再掩饰 三.创建eureka-client-provider-empdept-one提供 ...

  6. SpringCloud之Ribbon负载均衡策略

    Spring Cloud 微服务架构学习记录与示例 一.认识Ribbon 首先咱们需要认识下负载均衡,一般分为服务器端负载和客户端负载均衡. 服务器端负载均衡:比如Nginx.F5,请求达到服务器后由 ...

  7. Ribbon负载均衡策略与自定义配置new

    Ribbon负载均衡策略 配置 对调用的某个服务启用某种负载策略 1)通过配置文件配置 hello: ribbon: NFLoadBalancerRuleClassName:com.netflix.l ...

  8. Ribbon负载均衡策略与自定义配置

    Ribbon负载均衡策略 配置 对调用的某个服务启用某种负载策略 1)通过配置文件配置 hello: ribbon: NFLoadBalancerRuleClassName:com.netflix.l ...

  9. Spring Cloud微服务开发笔记5——Ribbon负载均衡策略规则定制

    上一篇文章单独介绍了Ribbon框架的使用,及其如何实现客户端对服务访问的负载均衡,但只是单独从Ribbon框架实现,没有涉及spring cloud.本文着力介绍Ribbon的负载均衡机制,下一篇文 ...

随机推荐

  1. mysql20170404代码实现

    CREATE DATABASE IF NOT EXISTS school; USE school; CREATE TABLE tblStudent( StuId ) NOT NULL PRIMARY ...

  2. B2460 [BeiJing2011]元素 线性基

    这个题是对刚才线性基的一个补充,就是中间有一些小贪心,贪心就很有意思,先按权值排序,然后就瞎搞就行了. 题干: Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们 ...

  3. PCB 全景图技术实现

    为了对3D模型理解更透,这里采用threejs(WebGL第三方库)实现,刚开始学习入门,为了能看明白基本上每行代码都注释. 如果仅仅是为了实现全景图,可以用photo-sphere-viewer.j ...

  4. php多个进程写文件

    多进程写文件function write_file($filename, $content){ $lock = $filename . '.lck'; $write_length = 0; while ...

  5. es6入门6--数组拓展运算符,Array.from()基本用法

    本文只是作为ES6入门第九章学习笔记,在整理知识点的同时,会加入部分个人思考与解答,若想知道更详细的介绍,还请阅读阮一峰大神的ES6入门 一.拓展运算符 ES6中新增了拓展运算(...)三个点,它的作 ...

  6. indeed 4.22 第一次网测

    1.第一题 没有看 2. 由于数据范围很小,所以每一层需要全排列,寻找最小的花费,然后所有层加起来就是最后的结果. #include<bits/stdc++.h> #define pb p ...

  7. Vue2-Editor 使用

    Vue-Editor底层采取的是quill.js,而quill.js采用的是html5的新属性classList,所以版本低于ie10会报错“无法获取未定义或 null 引用的属性‘confirm’” ...

  8. Android 解析JSON

    上次讲了XML格式数据的解析方式,这次要说的是如何解析JSON数据格式,相对与XML,JSON解析数据的方式在于它的体积更小,在网络上传输可以更省流量. 这次在网上找到一个中国天气json数据的API ...

  9. Css小动画

    html页面: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF ...

  10. SQL Server 置疑、可疑、正在恢复

    一.出错情况 有些时候当你重启了数据库服务,会发现有些数据库变成了正在恢复.置疑.可疑等情况,这个时候DBA就会很紧张了,下面是一些在实践中得到证明的方法. 在一次重启数据库服务后,数据库显示正在恢复 ...