Nginx負載均衡算法之加權(quán)輪詢 java實現(xiàn)

今天在看《大型網(wǎng)站技術(shù)架構(gòu)》時讳癌,里面介紹負載均衡算法時提到加權(quán)輪詢(Weighted Round Robin) , 對其具體實現(xiàn)不太熟悉巷疼,網(wǎng)上的介紹有點亂搀擂,不太好理解,所以這里自己實現(xiàn)一下這個算法吗跋,以自己能通俗理解的方式記錄一下

一. 加權(quán)輪詢在nginx中的部分配置
http {  
    upstream cluster {  
        server 192.168.1.2 weight=5;  
        server 192.168.1.3 weight=3;  
        server 192.168.1.4 weight=1;  
    }  
    ...
location / {
       proxy_set_header X-Real-IP $remote_addr;               //返回真實IP
       proxy_pass http://cluster;                           //代理指向cluster 
   }

二. 加權(quán)輪詢算法介紹

  1. 由于不同服務(wù)器的配置侧戴、部署的應(yīng)用不同,其處理能力會不一樣。所以救鲤,加權(quán)輪詢算法的原理就是:根據(jù)服務(wù)器的不同處理能力久窟,給每個服務(wù)器分配不同的權(quán)值,使其能夠接受相應(yīng)權(quán)值數(shù)的服務(wù)請求本缠。
  2. Nginx加權(quán)輪詢算法中斥扛,每個節(jié)點有三個權(quán)重變量
  • weight : 配置的權(quán)重,即在配置文件或初始化時約定好的每個節(jié)點的權(quán)重
  • currentWeight : 節(jié)點當前權(quán)重丹锹,會一直變化
  • effectiveWeight :有效權(quán)重稀颁,初始值為weight, 通訊過程中發(fā)現(xiàn)節(jié)點異常,則-1 楣黍,之后再次選取本節(jié)點匾灶,調(diào)用成功一次則+1,直達恢復(fù)到weight 租漂。 用于健康檢查阶女,處理異常節(jié)點,降低其權(quán)重哩治。
  1. 算法邏輯
    (1) 輪詢所有節(jié)點秃踩,計算當前狀態(tài)下所有節(jié)點的effectiveWeight之和totalWeight
    (2) currentWeight = currentWeight + effectiveWeight; 選出所有節(jié)點中currentWeight中最大的一個節(jié)點作為選中節(jié)點业筏;
    (3) 選中節(jié)點的currentWeight = currentWeight - totalWeight憔杨;
    注:(為了簡單清晰,后面的實現(xiàn)不考慮健康檢查effectiveWeight這個功能實現(xiàn)蒜胖,假設(shè)所有節(jié)點都是100%可用消别,所以上面的邏輯要把使用effectiveWeight的地方換成weight
  2. 例子
    假設(shè)有三個節(jié)點{serverA , serverB , serverC} , 權(quán)重為分別為{4,3,2} ,現(xiàn)在請求7次的分配情況如下:
請求次數(shù) 請求前currentWeight 選中的節(jié)點 請求后currentWeight
1 [ serverA= 4,serverB= 3,serverC= 2 ] serverA [ serverA= -1,serverB= 6,serverC= 4 ]
2 [ serverA= -1,serverB= 6,serverC= 4 ] serverB [ serverA= 3,serverB= 0,serverC= 6 ]
3 [ serverA= 3,serverB= 0,serverC= 6 ] serverC [ serverA= 7,serverB= 3,serverC= -1 ]
4 [ serverA= 7,serverB=3,serverC= -1 ] serverA [ serverA= 2,serverB= 6,serverC= 1 ]
5 [ serverA= 2,serverB= 6,serverC= 1 ] serverB [ serverA= 6,serverB= 0,serverC= 3 ]
6 [ serverA= 6,serverB= 0,serverC= 3 ] serverA [ serverA= 1,serverB= 3,serverC= 5 ]
7 [ serverA= 1,serverB= 3,serverC= 5 ] serverC [ serverA= 5,serverB= 6,serverC= -2 ]

totaoWeight = 4 + 3 + 2 = 9 ,
第一次請求 serverA= 4 + 4(原始比重) = 8 ,serverB= 3+3(原始比重) = 6,serverC= 2+2(原始比重) = 4 , 最大的是serverA , 所以 serverA= 8 - 9 (權(quán)重總和) = -1 台谢,所以最后值為 serverA= -1,serverB= 6,serverC= 4
第二次請求 serverA= -1 + 4(原始比重) = 3 ,serverB= 6+3(原始比重) = 9,serverC= 4+2(原始比重) = 6 寻狂, 最大的是serverB , 所以 serverB= 9 - 9 (權(quán)重總和) = 0 ,所以最后值為 serverA= 3,serverB= 0,serverC= 6
依此類推...

三. 代碼實現(xiàn)(java)

  • DemoApplication main方法
package com.example.demo;

public class DemoApplication {
    public static void main(String[] args) {
        /**
         * 假設(shè)有三個服務(wù)器權(quán)重配置如下:
         * server A  weight = 4 ;
         * server B  weight = 3 ;
         * server C  weight = 2 ;
         */
        Node serverA = new Node("serverA", 4);
        Node serverB = new Node("serverB", 3);
        Node serverC = new Node("serverC", 2);
        
        SmoothWeightedRoundRobin smoothWeightedRoundRobin = new SmoothWeightedRoundRobin(serverA,serverB ,serverC);
        for (int i = 0; i < 7; i++) {
            Node i1 = smoothWeightedRoundRobin.select();
            System.out.println(i1.getServerName());
        }
    }
}
  • SmoothWeightedRoundRobin 加權(quán)輪詢算法
package com.example.demo;

import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

public class SmoothWeightedRoundRobin {
    private volatile List<Node> nodeList = new ArrayList<>() ; // 保存權(quán)重
    private ReentrantLock lock = new ReentrantLock() ;

    public SmoothWeightedRoundRobin(Node ...nodes) {
        for (Node node : nodes) {
            nodeList.add(node) ;
        }
    }

    public Node select(){
        try {
            lock.lock();
            return this.selectInner() ;
        }finally {
            lock.unlock();
        }
    }

    private Node selectInner(){
        int totalWeight = 0 ;
        Node maxNode = null ;
        int maxWeight = 0 ;

        for (int i = 0; i < nodeList.size(); i++) {
            Node n = nodeList.get(i);
            totalWeight += n.getWeight() ;

            // 每個節(jié)點的當前權(quán)重要加上原始的權(quán)重
            n.setCurrentWeight(n.getCurrentWeight() + n.getWeight());

            // 保存當前權(quán)重最大的節(jié)點
            if (maxNode == null || maxWeight < n.getCurrentWeight() ) {
                maxNode = n ;
                maxWeight = n.getCurrentWeight() ;
            }
        }
        // 被選中的節(jié)點權(quán)重減掉總權(quán)重
        maxNode.setCurrentWeight(maxNode.getCurrentWeight() - totalWeight);

//        nodeList.forEach(node -> System.out.print(node.getCurrentWeight()));
        return maxNode ;
    }
}
  • Node 服務(wù)節(jié)點
package com.example.demo;

public class Node {
    private final int weight ;  // 初始權(quán)重 (保持不變)
    private final String serverName ; // 服務(wù)名

    private int currentWeight ; // 當前權(quán)重

    public Node( String serverName, int weight) {
        this.weight = weight;
        this.serverName = serverName ;
        this.currentWeight = weight ;
    }

    public int getCurrentWeight() {
        return currentWeight;
    }

    public int getWeight() {
        return weight;
    }

    public void setCurrentWeight(int currentWeight) {
        this.currentWeight = currentWeight;
    }

    public String getServerName() {
        return serverName;
    }
}

這個算法相對保證了的平滑性和均勻性

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末对碌,一起剝皮案震驚了整個濱河市荆虱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌朽们,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诉位,死亡現(xiàn)場離奇詭異骑脱,居然都是意外死亡,警方通過查閱死者的電腦和手機苍糠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門叁丧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事拥娄∥们拢” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵稚瘾,是天一觀的道長牡昆。 經(jīng)常有香客問我,道長摊欠,這世上最難降的妖魔是什么丢烘? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮些椒,結(jié)果婚禮上播瞳,老公的妹妹穿的比我還像新娘。我一直安慰自己免糕,他們只是感情好赢乓,可當我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著石窑,像睡著了一般骏全。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上尼斧,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天姜贡,我揣著相機與錄音,去河邊找鬼棺棵。 笑死楼咳,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的烛恤。 我是一名探鬼主播母怜,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼缚柏!你這毒婦竟也來了苹熏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤币喧,失蹤者是張志新(化名)和其女友劉穎轨域,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杀餐,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡干发,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了史翘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枉长。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡冀续,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出必峰,到底是詐尸還是另有隱情洪唐,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布吼蚁,位于F島的核電站凭需,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏桂敛。R本人自食惡果不足惜功炮,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望术唬。 院中可真熱鬧薪伏,春花似錦、人聲如沸粗仓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽借浊。三九已至塘淑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蚂斤,已是汗流浹背存捺。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留曙蒸,地道東北人捌治。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像纽窟,于是被迫代替她去往敵國和親肖油。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 四層和七層負載均衡的特點 四層負載均衡:即在OSI第4層工作臂港,就是TCP層森枪,可以根據(jù)IP+端口進行負載均衡。此種L...
    Net夜風(fēng)閱讀 6,500評論 0 1
  • 首先聲明审孽,寫這個主要是因為最近同事面試的時候县袱,面試官題了一個問題,是關(guān)于負載均衡的瓷胧。以及負載均衡中輪詢算法的具體實...
    Tomy_Jx_Li閱讀 2,126評論 1 1
  • 內(nèi)容1內(nèi)容2內(nèi)容3
    xeklr閱讀 212評論 0 0
  • 楚姒在父母的墳塋前重重的磕了三個頭显拳,額頭上浸了血,凝素心疼壞了在楚姒磕完頭之后搓萧,趕忙就拿了止血散和素雅的繃帶出來給...
    白凰子羅閱讀 1,135評論 0 0