天天看點

【微服務】SpringCloud Ribbon 負載均衡随機通路算法

​github 解析源碼:https://github.com/Netflix/ribbon/blob/master/ribbonloadbalancer/src/main/java/com/netflix/loadbalancer/RandomRule.java​

1.Ribbon 負載均衡算法架構圖

【微服務】SpringCloud Ribbon 負載均衡随機通路算法
總結:可以看出Ribbon架構采用的都是基于一個接口提供規範,抽象類實作基礎功能,子類繼承抽象類 實作自己特有的算法。而常見的java 中間件常用架構都是采用類似的思想進行架構的設計。

2.随機算法代碼解析

package com.hblg.myrule;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @author i
 * @create 2020/2/19 17:46
 * @Description  RandomRule Ribbon随機通路算法
 */
//繼承第二階梯的抽象類
public class RandomRule extends AbstractLoadBalancerRule {

    /**
     * Randomly choose from all living servers
     */
    public Server choose(ILoadBalancer lb, Object key) {
        //先判斷負載均衡是否為空 為空直接傳回
        if (lb == null) {
            return null;
        }
        Server server = null;

        //使用while 而不是用if 為的是在server==null 在進行依次判斷 避免因多線程操作server資料的線程安全問題
        while (server == null) {
            //如果目前線程是中斷狀态 直接傳回
            if (Thread.interrupted()) {
                return null;
            }
            //擷取到線上微服務清單
            List<Server> upList = lb.getReachableServers();
            //擷取到所有包含線上和可能因網絡擁堵出現的異常服務清單
            List<Server> allList = lb.getAllServers();
            //擷取到所有的服務的數量
            int serverCount = allList.size();
            //如果數量為0 直接傳回null
            if (serverCount == 0) {
                /*
                 * No servers. End regardless of pass, because subsequent passes
                 * only get more restrictive.
                 */
                return null;
            }
            //根據目前服務清單數量 随機生成一個生産者節點下标
            int index = chooseRandomInt(serverCount);
            server = upList.get(index);

            //如果目前server節點為null 目前線程讓步 繼續下一次
            if (server == null) {
                /*
                 * The only time this should happen is if the server list were
                 * somehow trimmed. This is a transient condition. Retry after
                 * yielding.
                 */
                Thread.yield();
                continue;
            }

            //如果目前Server節點 是活躍狀态直接傳回 使用
            if (server.isAlive()) {
                return (server);
            }
            //為了避免其他情況的出現 設定目前Server節點為null 線程讓步 
            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }

        return server;

    }

    /***
     * ThreadLocalRandom用内部生成的種子進行初始化,可能不會被修改。
     * 适用時,在并發程式中使用ThreadLocalRandom而不是共享的Random對象通常會遇到更少的開銷和争用。
     * 當多個任務(例如,每個ForkJoinTask )線上程池中并行使用随機數時,使用ThreadLocalRandom是特别合适的。
     * @param serverCount
     * @return
     */
    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }
}