<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringCloud的負(fù)載均衡

          共 51612字,需瀏覽 104分鐘

           ·

          2021-03-14 18:19

          點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”

          優(yōu)質(zhì)文章,第一時(shí)間送達(dá)

            作者 |  拾萬(wàn)個(gè)為什么

          來(lái)源 |  urlify.cn/iuQJv2

          一.什么是負(fù)載均衡

            負(fù)載均衡(Load-balance LB),指的是將用戶的請(qǐng)求平攤分配到各個(gè)服務(wù)器上,從而達(dá)到系統(tǒng)的高可用。常見(jiàn)的負(fù)載均衡軟件有Nginx、lvs等。

           

          二.負(fù)載均衡的簡(jiǎn)單分類

            1)集中式LB:集中式負(fù)載均衡指的是,在服務(wù)消費(fèi)者(client)和服務(wù)提供者(provider)之間提供負(fù)載均衡設(shè)施,通過(guò)該設(shè)施把消費(fèi)者(client)的請(qǐng)求通過(guò)某種策略轉(zhuǎn)發(fā)給服務(wù)提供者(provider),常見(jiàn)的集中式負(fù)載均衡是Nginx;

            2)進(jìn)程式LB:將負(fù)載均衡的邏輯集成到消費(fèi)者(client)身上,即消費(fèi)者從服務(wù)注冊(cè)中心獲取服務(wù)列表,獲知有哪些地址可用,再?gòu)倪@些地址里選出合適的服務(wù)器,springCloud的Ribbon就是一個(gè)進(jìn)程式的負(fù)載均衡工具。

          三.為什么需要做負(fù)載均衡

            1) 不做負(fù)載均衡,可能導(dǎo)致某臺(tái)機(jī)子負(fù)荷太重而掛掉;

            2)導(dǎo)致資源浪費(fèi),比如某些機(jī)子收到太多的請(qǐng)求,肯定會(huì)導(dǎo)致某些機(jī)子收到很少請(qǐng)求甚至收不到請(qǐng)求,這樣會(huì)浪費(fèi)系統(tǒng)資源。

           

          四.springCloud如何開(kāi)啟負(fù)載均衡

            1)在消費(fèi)者子工程的pom.xml文件的加入相關(guān)依賴(https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon/1.4.7.RELEASE);

          <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-ribbon</artifactId>
              <version>1.4.7.RELEASE</version>
          </dependency>

             消費(fèi)者需要獲取服務(wù)注冊(cè)中心的注冊(cè)列表信息,把Eureka的依賴包也放進(jìn)pom.xml

           <dependency>
                   <groupId>org.springframework.cloud</groupId>
                   <artifactId>spring-cloud-starter-eureka-server</artifactId>
                   <version>1.4.7.RELEASE</version>
            </dependency>

            2)在application.yml里配置服務(wù)注冊(cè)中心的信息

            在該消費(fèi)者(client)的application.yml里配置Eureka的信息,至于如何啟動(dòng)一個(gè)springCloud項(xiàng)目,請(qǐng)看這篇博客https://www.cnblogs.com/fengrongriup/p/14464208.html

          #配置Eureka
          eureka:
            client:
              #是否注冊(cè)自己到服務(wù)注冊(cè)中心,消費(fèi)者不用提供服務(wù)
              register-with-eureka: false
              service-url:
                #訪問(wèn)的url
                defaultZone: http://localhost:8002/eureka/

            3)在消費(fèi)者啟動(dòng)類上面加上注解@EnableEurekaClient

          @EnableEurekaClient

            

            4)在配置文件的Bean上加上

              @Bean
              @LoadBalanced
              public RestTemplate getRestTemplate(){
                  return new RestTemplate();
              }

          五.IRule

           什么是IRule

            IRule接口代表負(fù)載均衡的策略,它的不同的實(shí)現(xiàn)類代表不同的策略,它的四種實(shí)現(xiàn)類和它的關(guān)系如下()

           

          說(shuō)明一下(idea找Irule的方法:ctrl+n   填入IRule進(jìn)行查找)

          1.RandomRule:表示隨機(jī)策略,它將從服務(wù)清單中隨機(jī)選擇一個(gè)服務(wù);

          public class RandomRule extends AbstractLoadBalancerRule {
              public RandomRule() {
              }

              @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
              //傳入一個(gè)負(fù)載均衡器
              public Server choose(ILoadBalancer lb, Object key) {
                  if (lb == null) {
                      return null;
                  } else {
                      Server server = null;
                      while(server == null) {
                          if (Thread.interrupted()) {
                              return null;
                          }
                          //通過(guò)負(fù)載均衡器獲取對(duì)應(yīng)的服務(wù)列表
                          List<Server> upList = lb.getReachableServers();
                          //通過(guò)負(fù)載均衡器獲取全部服務(wù)列表
                          List<Server> allList = lb.getAllServers();
                          int serverCount = allList.size();
                          if (serverCount == 0) {
                              return null;
                          }
                          //獲取一個(gè)隨機(jī)數(shù)
                          int index = this.chooseRandomInt(serverCount);
                          //通過(guò)這個(gè)隨機(jī)數(shù)從列表里獲取服務(wù)
                          server = (Server)upList.get(index);
                          if (server == null) {
                              //當(dāng)前線程轉(zhuǎn)為就緒狀態(tài),讓出cpu
                              Thread.yield();
                          } else {
                              if (server.isAlive()) {
                                  return server;
                              }

                              server = null;
                              Thread.yield();
                          }
                      }

                      return server;
                  }
              }

            小結(jié):通過(guò)獲取到的所有服務(wù)的數(shù)量,以這個(gè)數(shù)量為標(biāo)準(zhǔn)獲取一個(gè)(0,服務(wù)數(shù)量)的數(shù)作為獲取服務(wù)實(shí)例的下標(biāo),從而獲取到服務(wù)實(shí)例

           

          2.ClientConfigEnabledRoundRobinRule:ClientConfigEnabledRoundRobinRule并沒(méi)有實(shí)現(xiàn)什么特殊的處理邏輯,但是他的子類可以實(shí)現(xiàn)一些高級(jí)策略, 當(dāng)一些本身的策略無(wú)法實(shí)現(xiàn)某些需求的時(shí)候,它也可以做為父類幫助實(shí)現(xiàn)某些策略,一般情況下我們都不會(huì)使用它;

          public class ClientConfigEnabledRoundRobinRule extends AbstractLoadBalancerRule {
              //使用“4”中的RoundRobinRule策略
              RoundRobinRule roundRobinRule = new RoundRobinRule();

              public ClientConfigEnabledRoundRobinRule() {
              }

              public void initWithNiwsConfig(IClientConfig clientConfig) {
                  this.roundRobinRule = new RoundRobinRule();
              }

              public void setLoadBalancer(ILoadBalancer lb) {
                  super.setLoadBalancer(lb);
                  this.roundRobinRule.setLoadBalancer(lb);
              }

              public Server choose(Object key) {
                  if (this.roundRobinRule != null) {
                      return this.roundRobinRule.choose(key);
                  } else {
                      throw new IllegalArgumentException("This class has not been initialized with the RoundRobinRule class");
                  }
              }
          }

            小結(jié):用來(lái)作為父類,子類通過(guò)實(shí)現(xiàn)它來(lái)實(shí)現(xiàn)一些高級(jí)負(fù)載均衡策略

           

          1)ClientConfigEnabledRoundRobinRule的子類BestAvailableRule:從該策略的名字就可以知道,bestAvailable的意思是最好獲取的,該策略的作用是獲取到最空閑的服務(wù)實(shí)例;

          public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule {
              //注入負(fù)載均衡器,它可以選擇服務(wù)實(shí)例
              private LoadBalancerStats loadBalancerStats;

              public BestAvailableRule() {
              }

              public Server choose(Object key) {
                  //假如負(fù)載均衡器實(shí)例為空,采用它父類的負(fù)載均衡機(jī)制,也就是輪詢機(jī)制,因?yàn)樗母割惒捎玫木褪禽喸儥C(jī)制
                  if (this.loadBalancerStats == null) {
                      return super.choose(key);
                  } else {
                      //獲取所有服務(wù)實(shí)例并放入列表里
                      List<Server> serverList = this.getLoadBalancer().getAllServers();
                      //并發(fā)量
                      int minimalConcurrentConnections = 2147483647;
                      long currentTime = System.currentTimeMillis();
                      Server chosen = null;
                      Iterator var7 = serverList.iterator();
                      //遍歷服務(wù)列表
                      while(var7.hasNext()) {
                          Server server = (Server)var7.next();
                          ServerStats serverStats = this.loadBalancerStats.getSingleServerStat(server);
                          //淘汰掉已經(jīng)負(fù)載的服務(wù)實(shí)例
                          if (!serverStats.isCircuitBreakerTripped(currentTime)) {
                              //獲得當(dāng)前服務(wù)的請(qǐng)求量(并發(fā)量)
                              int concurrentConnections = serverStats.getActiveRequestsCount(currentTime);
                              //找出并發(fā)了最小的服務(wù)
                              if (concurrentConnections < minimalConcurrentConnections) {
                                  minimalConcurrentConnections = concurrentConnections;
                                  chosen = server;
                              }
                          }
                      }

                      if (chosen == null) {
                          return super.choose(key);
                      } else {
                          return chosen;
                      }
                  }
              }

              public void setLoadBalancer(ILoadBalancer lb) {
                  super.setLoadBalancer(lb);
                  if (lb instanceof AbstractLoadBalancer) {
                      this.loadBalancerStats = ((AbstractLoadBalancer)lb).getLoadBalancerStats();
                  }

              }
          }

             小結(jié):ClientConfigEnabledRoundRobinRule子類之一,獲取到并發(fā)了最少的服務(wù)

           

          2)ClientConfigEnabledRoundRobinRule的另一個(gè)子類是PredicateBasedRule:通過(guò)源碼可以看出它是一個(gè)抽象類,它的抽象方法getPredicate()返回一個(gè)AbstractServerPredicate的實(shí)例,然后它的choose方法調(diào)用AbstractServerPredicate類的chooseRoundRobinAfterFiltering方法獲取具體的Server實(shí)例并返回

          public abstract class PredicateBasedRule extends ClientConfigEnabledRoundRobinRule {
              public PredicateBasedRule() {
              }
              //獲取AbstractServerPredicate對(duì)象
              public abstract AbstractServerPredicate getPredicate();

              public Server choose(Object key) {
                  //獲取當(dāng)前策略的負(fù)載均衡器
                  ILoadBalancer lb = this.getLoadBalancer();
                  //通過(guò)AbstractServerPredicate的子類過(guò)濾掉一部分實(shí)例(它實(shí)現(xiàn)了Predicate)
                  //以輪詢的方式從過(guò)濾后的服務(wù)里選擇一個(gè)服務(wù)
                  Optional<Server> server = this.getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
                  return server.isPresent() ? (Server)server.get() : null;
              }
          }

            再看看它的chooseRoundRobinAfterFiltering()方法是如何實(shí)現(xiàn)的

          public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
                  List<Server> eligible = this.getEligibleServers(servers, loadBalancerKey);
                  return eligible.size() == 0 ? Optional.absent() : Optional.of(eligible.get(this.incrementAndGetModulo(eligible.size())));
              }

            是這樣的,先通過(guò)this.getEligibleServers(servers, loadBalancerKey)方法獲取一部分實(shí)例,然后判斷這部分實(shí)例是否為空,如果不為空則調(diào)用eligible.get(this.incrementAndGetModulo(eligible.size())方法從這部分實(shí)例里獲取一個(gè)服務(wù),點(diǎn)進(jìn)this.getEligibleServers看

          public List<Server> getEligibleServers(List<Server> servers, Object loadBalancerKey) {
                  if (loadBalancerKey == null) {
                      return ImmutableList.copyOf(Iterables.filter(servers, this.getServerOnlyPredicate()));
                  } else {
                      List<Server> results = Lists.newArrayList();
                      Iterator var4 = servers.iterator();

                      while(var4.hasNext()) {
                          Server server = (Server)var4.next();
                          //條件滿足
                          if (this.apply(new PredicateKey(loadBalancerKey, server))) {
                              //添加到集合里
                              results.add(server);
                          }
                      }

                      return results;
                  }
              }

            getEligibleServers方法是根據(jù)this.apply(new PredicateKey(loadBalancerKey, server))進(jìn)行過(guò)濾的,如果滿足,就添加到返回的集合中。符合什么條件才可以進(jìn)行過(guò)濾呢?可以發(fā)現(xiàn),apply是用this調(diào)用的,this指的是AbstractServerPredicate(它的類對(duì)象),但是,該類是個(gè)抽象類,該實(shí)例是不存在的,需要子類去實(shí)現(xiàn),它的子類在這里暫時(shí)不是看了,以后有空再深入學(xué)習(xí)下,它的子類如下,實(shí)現(xiàn)哪個(gè)子類,就用什么 方式過(guò)濾。

             再回到chooseRoundRobinAfterFiltering()方法,剛剛說(shuō)完它通過(guò) getEligibleServers方法過(guò)濾并獲取到一部分實(shí)例,然后再通過(guò)this.incrementAndGetModulo(eligible.size())方法從這部分實(shí)例里選擇一個(gè)實(shí)例返回,該方法的意思是直接返回下一個(gè)整數(shù)(索引值),通過(guò)該索引值從返回的實(shí)例列表中取得Server實(shí)例。

          private int incrementAndGetModulo(int modulo) {
                  //當(dāng)前下標(biāo)
                  int current;
                  //下一個(gè)下標(biāo)
                  int next;
                  do {
                      //獲得當(dāng)前下標(biāo)值
                      current = this.nextIndex.get();
                      next = (current + 1) % modulo;
                  } while(!this.nextIndex.compareAndSet(current, next) || current >= modulo);

                  return current;
              }

            源碼擼明白了,再來(lái)理一下chooseRoundRobinAfterFiltering()的思路:先通過(guò)getEligibleServers()方法獲得一部分服務(wù)實(shí)例,再?gòu)倪@部分服務(wù)實(shí)例里拿到當(dāng)前服務(wù)實(shí)例的下一個(gè)服務(wù)對(duì)象使用。

            小結(jié):通過(guò)AbstractServerPredicate的chooseRoundRobinAfterFiltering方法進(jìn)行過(guò)濾,獲取備選的服務(wù)實(shí)例清單,然后用線性輪詢選擇一個(gè)實(shí)例,是一個(gè)抽象類,過(guò)濾策略在AbstractServerPredicate的子類中具體實(shí)現(xiàn)

           

          3.RetryRule:是對(duì)選定的負(fù)載均衡策略加上重試機(jī)制,即在一個(gè)配置好的時(shí)間段內(nèi)(默認(rèn)500ms),當(dāng)選擇實(shí)例不成功,則一直嘗試使用subRule的方式選擇一個(gè)可用的實(shí)例,在調(diào)用時(shí)間到達(dá)閥值的時(shí)候還沒(méi)找到可用服務(wù),則返回空,如果沒(méi)有配置負(fù)載策略,默認(rèn)輪詢(即“4”中的輪詢);

            先貼上它的源碼

          public class RetryRule extends AbstractLoadBalancerRule {
              //從這可以看出,默認(rèn)使用輪詢機(jī)制
              IRule subRule = new RoundRobinRule();
              //500秒的閥值
              long maxRetryMillis = 500L;
              //無(wú)參構(gòu)造函數(shù)
              public RetryRule() {
              }
              //使用輪詢機(jī)制
              public RetryRule(IRule subRule) {
                  this.subRule = (IRule)(subRule != null ? subRule : new RoundRobinRule());
              }

              public RetryRule(IRule subRule, long maxRetryMillis) {
                  this.subRule = (IRule)(subRule != null ? subRule : new RoundRobinRule());
                  this.maxRetryMillis = maxRetryMillis > 0L ? maxRetryMillis : 500L;
              }
              
              public void setRule(IRule subRule) {
                  this.subRule = (IRule)(subRule != null ? subRule : new RoundRobinRule());
              }

              public IRule getRule() {
                  return this.subRule;
              }
              //設(shè)置最大耗時(shí)時(shí)間(閥值),最多重試多久
              public void setMaxRetryMillis(long maxRetryMillis) {
                  if (maxRetryMillis > 0L) {
                      this.maxRetryMillis = maxRetryMillis;
                  } else {
                      this.maxRetryMillis = 500L;
                  }

              }
              //獲取重試的時(shí)間
              public long getMaxRetryMillis() {
                  return this.maxRetryMillis;
              }
              //設(shè)置負(fù)載均衡器,用以獲取服務(wù)
              public void setLoadBalancer(ILoadBalancer lb) {
                  super.setLoadBalancer(lb);
                  this.subRule.setLoadBalancer(lb);
              }
              //通過(guò)負(fù)載均衡器選擇服務(wù)
              public Server choose(ILoadBalancer lb, Object key) {
                  long requestTime = System.currentTimeMillis();
                  //當(dāng)前時(shí)間+閥值 = 截止時(shí)間
                  long deadline = requestTime + this.maxRetryMillis;
                  Server answer = null;
                  answer = this.subRule.choose(key);
                  //獲取到服務(wù)直接返回
                  if ((answer == null || !answer.isAlive()) && System.currentTimeMillis() < deadline) {
                      InterruptTask task = new InterruptTask(deadline - System.currentTimeMillis());
                      //獲取不到服務(wù)的情況下反復(fù)獲取
                      while(!Thread.interrupted()) {
                          answer = this.subRule.choose(key);
                          if (answer != null && answer.isAlive() || System.currentTimeMillis() >= deadline) {
                              break;
                          }

                          Thread.yield();
                      }

                      task.cancel();
                  }

                  return answer != null && answer.isAlive() ? answer : null;
              }

              public Server choose(Object key) {
                  return this.choose(this.getLoadBalancer(), key);
              }

              public void initWithNiwsConfig(IClientConfig clientConfig) {
              }
          }

            小結(jié):采用RoundRobinRule的選擇機(jī)制,進(jìn)行反復(fù)嘗試,當(dāng)花費(fèi)時(shí)間超過(guò)設(shè)置的閾值maxRetryMills時(shí),就返回null

           

          4.RoundRobinRule:輪詢策略,它會(huì)從服務(wù)清單中按照輪詢的方式依次選擇每個(gè)服務(wù)實(shí)例,它的工作原理是:直接獲取下一個(gè)可用實(shí)例,如果超過(guò)十次沒(méi)有獲取到可用的服務(wù)實(shí)例,則返回空且報(bào)出異常信息;

          public class RoundRobinRule extends AbstractLoadBalancerRule {
              private AtomicInteger nextServerCyclicCounter;
              private static final boolean AVAILABLE_ONLY_SERVERS = true;
              private static final boolean ALL_SERVERS = false;
              private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);

              public RoundRobinRule() {
                  this.nextServerCyclicCounter = new AtomicInteger(0);
              }

              public RoundRobinRule(ILoadBalancer lb) {
                  this();
                  this.setLoadBalancer(lb);
              }

              public Server choose(ILoadBalancer lb, Object key) {
                  if (lb == null) {
                      log.warn("no load balancer");
                      return null;
                  } else {
                      Server server = null;
                      int count = 0;

                      while(true) {
                          //選擇十次,十次都沒(méi)選到可用服務(wù)就返回空
                          if (server == null && count++ < 10) {
                              List<Server> reachableServers = lb.getReachableServers();
                              List<Server> allServers = lb.getAllServers();
                              int upCount = reachableServers.size();
                              int serverCount = allServers.size();
                              if (upCount != 0 && serverCount != 0) {
                                  int nextServerIndex = this.incrementAndGetModulo(serverCount);
                                  server = (Server)allServers.get(nextServerIndex);
                                  if (server == null) {
                                      Thread.yield();
                                  } else {
                                      if (server.isAlive() && server.isReadyToServe()) {
                                          return server;
                                      }

                                      server = null;
                                  }
                                  continue;
                              }

                              log.warn("No up servers available from load balancer: " + lb);
                              return null;
                          }

                          if (count >= 10) {
                              
                              log.warn("No available alive servers after 10 tries from load balancer: " + lb);
                          }

                          return server;
                      }
                  }
              }
              
              //遞增的形式實(shí)現(xiàn)輪詢
              private int incrementAndGetModulo(int modulo) {
                  int current;
                  int next;
                  do {
                      current = this.nextServerCyclicCounter.get();
                      next = (current + 1) % modulo;
                  } while(!this.nextServerCyclicCounter.compareAndSet(current, next));

                  return next;
              }

              public Server choose(Object key) {
                  return this.choose(this.getLoadBalancer(), key);
              }

              public void initWithNiwsConfig(IClientConfig clientConfig) {
              }
          }

            小結(jié):采用線性輪詢機(jī)制循環(huán)依次選擇每個(gè)服務(wù)實(shí)例,直到選擇到一個(gè)不為空的服務(wù)實(shí)例或循環(huán)次數(shù)達(dá)到10次   

           

          它有個(gè)子類WeightedResponseTimeRule,WeightedResponseTimeRule是對(duì)RoundRobinRule的優(yōu)化。WeightedResponseTimeRule在其父類的基礎(chǔ)上,增加了定時(shí)任務(wù)這個(gè)功能,通過(guò)啟動(dòng)一個(gè)定時(shí)任務(wù)來(lái)計(jì)算每個(gè)服務(wù)的權(quán)重,然后遍歷服務(wù)列表選擇服務(wù)實(shí)例,從而達(dá)到更加優(yōu)秀的分配效果。我們這里把這個(gè)類分為三部分:定時(shí)任務(wù),計(jì)算權(quán)值,選擇服務(wù)

          1)定時(shí)任務(wù)

          //定時(shí)任務(wù)
          void initialize(ILoadBalancer lb) {
                  if (this.serverWeightTimer != null) {
                      this.serverWeightTimer.cancel();
                  }

                  this.serverWeightTimer = new Timer("NFLoadBalancer-serverWeightTimer-" + this.name, true);
                 //開(kāi)啟一個(gè)任務(wù),每30秒執(zhí)行一次
                  this.serverWeightTimer.schedule(new WeightedResponseTimeRule.DynamicServerWeightTask(), 0L, (long)this.serverWeightTaskTimerInterval);
                  WeightedResponseTimeRule.ServerWeight sw = new WeightedResponseTimeRule.ServerWeight();
                  sw.maintainWeights();
                  Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                      public void run() {
                          WeightedResponseTimeRule.logger.info("Stopping NFLoadBalancer-serverWeightTimer-" + WeightedResponseTimeRule.this.name);
                          WeightedResponseTimeRule.this.serverWeightTimer.cancel();
                      }
                  }));
              }

          DynamicServerWeightTask()任務(wù)如下:

          class DynamicServerWeightTask extends TimerTask {
                  DynamicServerWeightTask() {
                  }

                  public void run() {
                      WeightedResponseTimeRule.ServerWeight serverWeight = WeightedResponseTimeRule.this.new ServerWeight();

                      try {
                          //計(jì)算權(quán)重
                          serverWeight.maintainWeights();
                      } catch (Exception var3) {
                          WeightedResponseTimeRule.logger.error("Error running DynamicServerWeightTask for {}", WeightedResponseTimeRule.this.name, var3);
                      }

                  }
              }

             小結(jié):調(diào)用initialize方法開(kāi)啟定時(shí)任務(wù),再在任務(wù)里計(jì)算服務(wù)的權(quán)重

           

          2)計(jì)算權(quán)重:第一步,先算出所有實(shí)例的響應(yīng)時(shí)間;第二步,再根據(jù)所有實(shí)例響應(yīng)時(shí)間,算出每個(gè)實(shí)例的權(quán)重

          //用來(lái)存儲(chǔ)權(quán)重
          private volatile List<Double> accumulatedWeights = new ArrayList();

          //內(nèi)部類
          class ServerWeight {
                  ServerWeight() {
                  }
                  //該方法用于計(jì)算權(quán)重
                  public void maintainWeights() {
                      //獲取負(fù)載均衡器
                      ILoadBalancer lb = WeightedResponseTimeRule.this.getLoadBalancer();
                      if (lb != null) {
                          if (WeightedResponseTimeRule.this.serverWeightAssignmentInProgress.compareAndSet(falsetrue)) {
                              try {
                                  WeightedResponseTimeRule.logger.info("Weight adjusting job started");
                                  AbstractLoadBalancer nlb = (AbstractLoadBalancer)lb;
                                  //獲得每個(gè)服務(wù)實(shí)例的信息
                                  LoadBalancerStats stats = nlb.getLoadBalancerStats();
                                  if (stats != null) {
                                      //實(shí)例的響應(yīng)時(shí)間
                                      double totalResponseTime = 0.0D;

                                      ServerStats ss;
                                      //累加所有實(shí)例的響應(yīng)時(shí)間
                                      for(Iterator var6 = nlb.getAllServers().iterator(); var6.hasNext(); totalResponseTime += ss.getResponseTimeAvg()) {
                                          Server server = (Server)var6.next();
                                          ss = stats.getSingleServerStat(server);
                                      }

                                      Double weightSoFar = 0.0D;
                                      List<Double> finalWeights = new ArrayList();
                                      Iterator var20 = nlb.getAllServers().iterator();
                                      //計(jì)算負(fù)載均衡器所有服務(wù)的權(quán)重,公式是weightSoFar = weightSoFar + weight-實(shí)例平均響應(yīng)時(shí)間
                                      while(var20.hasNext()) {
                                          Server serverx = (Server)var20.next();
                                          ServerStats ssx = stats.getSingleServerStat(serverx);
                                          double weight = totalResponseTime - ssx.getResponseTimeAvg();
                                          weightSoFar = weightSoFar + weight;
                                          finalWeights.add(weightSoFar);
                                      }

                                      WeightedResponseTimeRule.this.setWeights(finalWeights);
                                      return;
                                  }
                              } catch (Exception var16) {
                                  WeightedResponseTimeRule.logger.error("Error calculating server weights", var16);
                                  return;
                              } finally {
                                  WeightedResponseTimeRule.this.serverWeightAssignmentInProgress.set(false);
                              }

                          }
                      }
                  }
              }

          3)選擇服務(wù)

          @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
              public Server choose(ILoadBalancer lb, Object key) {
                  if (lb == null) {
                      return null;
                  } else {
                      Server server = null;

                      while(server == null) {
                          List<Double> currentWeights = this.accumulatedWeights;
                          if (Thread.interrupted()) {
                              return null;
                          }

                          List<Server> allList = lb.getAllServers();
                          int serverCount = allList.size();
                          if (serverCount == 0) {
                              return null;
                          }

                          int serverIndex = 0;
                        
                          double maxTotalWeight = currentWeights.size() == 0 ? 0.0D : (Double)currentWeights.get(currentWeights.size() - 1);
                          if (maxTotalWeight >= 0.001D && serverCount == currentWeights.size()) {
                              //生產(chǎn)0到最大權(quán)重值的隨機(jī)數(shù)
                              double randomWeight = this.random.nextDouble() * maxTotalWeight;
                              int n = 0;
                              //循環(huán)權(quán)重區(qū)間
                              for(Iterator var13 = currentWeights.iterator(); var13.hasNext(); ++n) {
                                  //獲取到循環(huán)的數(shù)
                                  Double d = (Double)var13.next();
                                  //假如隨機(jī)數(shù)在這個(gè)區(qū)間內(nèi),就拿該索引d服務(wù)列表獲取對(duì)應(yīng)的實(shí)例
                                  if (d >= randomWeight) {
                                      serverIndex = n;
                                      break;
                                  }
                              }

                              server = (Server)allList.get(serverIndex);
                          } else {
                              server = super.choose(this.getLoadBalancer(), key);
                              if (server == null) {
                                  return server;
                              }
                          }

                          if (server == null) {
                              Thread.yield();
                          } else {
                              if (server.isAlive()) {
                                  return server;
                              }

                              server = null;
                          }
                      }

                      return server;
                  }
              }

            小結(jié):首先生成了一個(gè)[0,最大權(quán)重值) 區(qū)間內(nèi)的隨機(jī)數(shù),然后遍歷權(quán)重列表,假如當(dāng)前隨機(jī)數(shù)在這個(gè)區(qū)間內(nèi),就通過(guò)該下標(biāo)獲得對(duì)應(yīng)的服務(wù)。






          鋒哥最新SpringCloud分布式電商秒殺課程發(fā)布

          ??????

          ??長(zhǎng)按上方微信二維碼 2 秒





          感謝點(diǎn)贊支持下哈 

          瀏覽 57
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕一区二区三区在线观看 | 性淫影院 | 欧美日韩中文视频 | 在线精品国产视频观看 | 黄色国产无码 |