java 平滑加權輪詢算法實現與講解

                      java 平滑加權輪詢算法實現與分析

廢話,可直接跳過: 有一個需求,須要在代碼層面上 實現 灰度 發佈,有一種很簡單的辦法就是取餘,好比  當前時間戳(或者業務ID) % 10 對於10取餘, 餘1,2,3 的走 邏輯A,其餘的走邏輯B,從而達到灰度發佈的效果,可是我不甘於此,我想設計的複雜點,就去研究了下nginx相關的輪詢算法, 我中意了一個 平滑加權輪詢算法(再簡單的東西,只要你願意去思考,總能學到東西,不甘於現狀)。

 

 

  • 平滑加權輪詢算法  ---  直接貼代碼

  • 平滑加權輪詢算法 ---  分析

 

1、平滑加權輪詢算法  ---  直接貼代碼

public class SmoothServer {

    public SmoothServer(String ip, int weight, int curWeight) {
        this.ip = ip;
        this.weight = weight;
        this.curWeight = curWeight;
    }

    private String ip;

    private int weight;

    private int curWeight;

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public int getCurWeight() {
        return curWeight;
    }

    public void setCurWeight(int curWeight) {
        this.curWeight = curWeight;
    }
}
服務器實體類
public class SmoothWeightRoundRobin {

    /**初始化全部的服務器**/
    List<SmoothServer> servers = new ArrayList<>();

    /**服務器權重總和*/
    private int weightCount;

    public void init(List<SmoothServer> servers) {
        this.servers = servers;
        this.weightCount = this.servers.stream().map(server -> server.getWeight()).reduce(0, (l, r) -> l + r);

    }

    /**獲取須要執行的服務器**/
    public SmoothServer getServer() {
        SmoothServer tmpSv = null;

        for (SmoothServer sv : servers) {
            sv.setCurWeight(sv.getWeight() + sv.getCurWeight());
            if (tmpSv == null || tmpSv.getCurWeight() < sv.getCurWeight()) tmpSv = sv;
        }

        tmpSv.setCurWeight(tmpSv.getCurWeight() - weightCount);
        return tmpSv;
    }

}
平滑權衡算法
public class RobinExecute {

    /** 線程使用完不會清除該變量,會一直保留着,因爲線程 池化因此不用擔憂內存泄漏 **/
    private ThreadLocal<SmoothWeightRoundRobin> weightRoundRobinTl = new ThreadLocal<SmoothWeightRoundRobin>();

    private ReentrantLock lock = new ReentrantLock();

    /** 爲何添加volatile,是由於 ReentrantLock 並不保證內存可見性 **/
    private volatile SmoothWeightRoundRobin smoothWeightRoundRobin;

    public static void main(String[] args) {

        RobinExecute robinExecute = new RobinExecute();

        /** ==================    TheadLocal   ========================**/
        robinExecute.acquireWeightRoundRobinOfTheadLocal().getServer();

        /** ==================    ReentrantLock 可重入鎖   ========================**/
        robinExecute.getLock().lock();  //notice: 注意此鎖會無休止的等待資源,若是使用此鎖,無比保證資源可以被拿到
        try {
            robinExecute.acquireWeightRoundRobinOfLock();
        } catch (Exception e) {
            e.printStackTrace();
        } finally { //確保必定要釋放鎖
            robinExecute.getLock().unlock();
        }

    }

    /**
     * 在分佈式狀況,第二種使用方式  使用cas ReentrantLock 可重入鎖
     * notice:
     * @return
     */
    public SmoothServer acquireWeightRoundRobinOfLock() {
        if (smoothWeightRoundRobin == null) {
            SmoothWeightRoundRobin weightRoundRobin = new SmoothWeightRoundRobin();
            List<SmoothServer> servers = new ArrayList<>();
            servers.add(new SmoothServer("191", 1, 0));
            servers.add(new SmoothServer("192", 2, 0));
            servers.add(new SmoothServer("194", 4, 0));
            weightRoundRobin.init(servers);
            smoothWeightRoundRobin = weightRoundRobin;
        }
        return smoothWeightRoundRobin.getServer();
    }

    /**
     * 在分佈式狀況,第一種使用方式  ThreadLock
     * notice: 只有在使用池化技術的狀況才建議使用此方式,不然達不到效果,還會形成內存泄漏
     * @return
     */
    public SmoothWeightRoundRobin acquireWeightRoundRobinOfTheadLocal() {
        return Optional.ofNullable(weightRoundRobinTl.get())
            .orElseGet(() -> {
                SmoothWeightRoundRobin weightRoundRobin = new SmoothWeightRoundRobin();
                List<SmoothServer> servers = new ArrayList<>();
                servers.add(new SmoothServer("191", 1, 0));
                servers.add(new SmoothServer("192", 2, 0));
                servers.add(new SmoothServer("194", 4, 0));
                weightRoundRobin.init(servers);
                weightRoundRobinTl.set(weightRoundRobin);
                return weightRoundRobin;
            });
    }

    public ReentrantLock getLock() {
        return lock;
    }

    public ThreadLocal<SmoothWeightRoundRobin> getWeightRoundRobinTl() {
        return weightRoundRobinTl;
    }
}
兩種使用方式(適用分佈式環境中)

 

2、平滑加權輪詢算法 ---  分析

 

 

相關文章
相關標籤/搜索