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


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

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

 

 

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

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

 

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

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;
    }
}
兩種使用方式(適用分布式環境中)

 

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

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM