<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    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è)為什么

    來源 |  urlify.cn/iuQJv2

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

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

     

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

      1)集中式LB:集中式負(fù)載均衡指的是,在服務(wù)消費(fèi)者(client)和服務(wù)提供者(provider)之間提供負(fù)載均衡設(shè)施,通過該設(shè)施把消費(fèi)者(client)的請(qǐng)求通過某種策略轉(zhuǎn)發(fā)給服務(wù)提供者(provider),常見的集中式負(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如何開啟負(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:
          #訪問的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)系如下()

     

    說明一下(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;
                    }
                    //通過負(fù)載均衡器獲取對(duì)應(yīng)的服務(wù)列表
                    List<Server> upList = lb.getReachableServers();
                    //通過負(fù)載均衡器獲取全部服務(wù)列表
                    List<Server> allList = lb.getAllServers();
                    int serverCount = allList.size();
                    if (serverCount == 0) {
                        return null;
                    }
                    //獲取一個(gè)隨機(jī)數(shù)
                    int index = this.chooseRandomInt(serverCount);
                    //通過這個(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é):通過獲取到的所有服務(wù)的數(shù)量,以這個(gè)數(shù)量為標(biāo)準(zhǔn)獲取一個(gè)(0,服務(wù)數(shù)量)的數(shù)作為獲取服務(wù)實(shí)例的下標(biāo),從而獲取到服務(wù)實(shí)例

     

    2.ClientConfigEnabledRoundRobinRule:ClientConfigEnabledRoundRobinRule并沒有實(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é):用來作為父類,子類通過實(shí)現(xiàn)它來實(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:通過源碼可以看出它是一個(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();
            //通過AbstractServerPredicate的子類過濾掉一部分實(shí)例(它實(shí)現(xiàn)了Predicate)
            //以輪詢的方式從過濾后的服務(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())));
        }

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

       再回到chooseRoundRobinAfterFiltering()方法,剛剛說完它通過 getEligibleServers方法過濾并獲取到一部分實(shí)例,然后再通過this.incrementAndGetModulo(eligible.size())方法從這部分實(shí)例里選擇一個(gè)實(shí)例返回,該方法的意思是直接返回下一個(gè)整數(shù)(索引值),通過該索引值從返回的實(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;
        }

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

      小結(jié):通過AbstractServerPredicate的chooseRoundRobinAfterFiltering方法進(jìn)行過濾,獲取備選的服務(wù)實(shí)例清單,然后用線性輪詢選擇一個(gè)實(shí)例,是一個(gè)抽象類,過濾策略在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í)候還沒找到可用服務(wù),則返回空,如果沒有配置負(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);
        }
        //通過負(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í)間超過設(shè)置的閾值maxRetryMills時(shí),就返回null

     

    4.RoundRobinRule:輪詢策略,它會(huì)從服務(wù)清單中按照輪詢的方式依次選擇每個(gè)服務(wù)實(shí)例,它的工作原理是:直接獲取下一個(gè)可用實(shí)例,如果超過十次沒有獲取到可用的服務(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) {
                    //選擇十次,十次都沒選到可用服務(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è)功能,通過啟動(dòng)一個(gè)定時(shí)任務(wù)來計(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);
           //開啟一個(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方法開啟定時(shí)任務(wù),再在任務(wù)里計(jì)算服務(wù)的權(quán)重

     

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

    //用來存儲(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),就通過該下標(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="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    狠狠干免费视频 | 大香蕉网成人电影 | 国产操B视频 | 天天色天天综合 | 伊人久久免费视频 |