奈學:傳授“帶權重的負載均衡實現演算法”獨家設計思路

奈學教育發表於2020-06-01

分散式系統中,大部分系統呼叫都會涉及到負載均衡,例如:客戶端發往服務端的請求首先到達反向代理,然後反向代理再透過負載均衡演算法將請求轉發到業務系統;或者後端業務系統各模組間的呼叫前,也需要透過負載均衡演算法選擇到一個目標節點。

一般情況下,我們對負載均衡的要求就是均勻,確保呼叫方的請求流量能夠均勻的傳送到我們冗餘部署的N個服務節點上,所以負載均衡的演算法一般使用隨機或輪詢都可以保證被呼叫結點流量的均勻。

真實情況下,往往由於部署服務的伺服器效能或資源分配等原因需要我們為服務結點設定不同的權重,權重高的結點可以分配多一些的流量,同時降低權重低的結點的流量比例。

這時負載均衡就不能簡單的使用隨機或者輪詢了,需要新增對權重的支援。接下來我們分析幾種帶權重的負載均衡演算法,並分析一下他們的優缺點:

一、使用隨機數 

設計思路如下:首先經過負載均衡後選擇到一個結點,然後我們根據權重值再做一道攔截,按權重按比例放行,實現按降低結點流量的效果。例如我們規定權重的範圍從0到10之間,0拒絕,10放行。權重值越高,分配的流量就越多。

最簡單的實現方案,可以使用隨機值,假設設定目標結點的權重值為7,當結點被負載均衡選中後,我們生成一個0到10之間的隨機數,小於7放行,大於7則不向目標結點傳送請求,需要從新做負載均衡計算,由此實現了將目標結點的流量降低到原來的70%。

方案實現起來很簡單,但問題也很明顯,我們都知道生成隨機數的計算會造成CPU的開銷,計算權重又發生在RPC呼叫過程中,所以每次RPC請求都會額外的增加一次隨機數計算,累積起來對CPU額外的開銷就很大了。我們可以進一步最佳化一下。

二、隨機陣列

我們可以使用一個隨機陣列代替上文描述的生成隨機數的策略,實現同樣效果的同時能夠減少CPU的計算量。接下來描述下隨機陣列演算法,同樣權重設計為0~10。

我們為每個被呼叫的結點都生成一個隨機陣列,陣列長度為10。空間分配好後用0和1填充陣列,0的個數與結點的權重值一樣,同時要保證0在陣列中出現的位置是隨機的。

我們生成一個代表權重為“4”的隨機陣列(4個0),如下圖所示:

和隨機數方案類似,我們在完成負載均衡計算後,進行權重攔截。這個時候我們可以透過訪問隨機陣列代替生成隨機數的計算,方案描述如下:記錄上一次訪問隨機陣列的位置,取陣列下一位置元素值,取到0則放行,1則拒絕,重新進行負載均衡計算。方案的思路是,輪詢訪問隨機陣列,到達隨機效果。因為陣列的內容是隨機的。

這兩種方案思路是一致的,都是在負載均衡計算後再加一道權重攔截。但這樣的問題是流量控制不精確,無法實現精確個節點按權重比例分配流量。我們可以換個思路,實現精確的流量控制。

三、 輪詢加權重負載策略

設計思路如下,設計一個權重因子,初始值為所有被呼叫的結點中最大權重值。負載均衡使用輪詢演算法,被選中結點權重值大於等於權重因子則可以呼叫,否則用下一結點的權重值與權重因子比較,一輪迴圈結束後如果沒有選中結點,則降低權重因子,繼續透過與權重因子比較進行選擇,直到選中為止。權重因子降為0後,恢復為最大權重值。虛擬碼如下:

上述虛擬碼中幾個變數意義如下:

  • i:當前輪詢的結點;

  • n:可選擇結點數量;

  • cw:權重因子;

  • gcd(s):權重因子每次降低的步長;

  • max(s):所有結點中最大的權重值;

  • W(si):結點Si的權重值;

  • Si:服務結點(S0~Sn-1,共n個)

權重因子的降低步長為所有結點權重值的最大公約數。

假設有4個結點,A,B,C,D,權重值分別為,8,6,4,2,各結點權重值得最大公約數為2,所以權重降低步長為2,透過上面的虛擬碼,我們推演下負載均衡的流量分配結果。

初始條件:

  • 1、i從0開始迴圈;

  • 2、權重因子為8(虛擬碼中初始化為0,減權重因子後小於0,被恢復為最大值)

第一次呼叫:i=0,A權重大於等於權重因子(8),可以呼叫A;

第二次呼叫:i=1,B權重小於8,不可以呼叫,繼續迴圈;

......

第二次呼叫會選擇哪個結點呢,以及後面的呼叫如何選擇的,歡迎大家在評留言給出自己的推演結果。

掃碼下方二維碼領取更多免費課程及學習資料

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69976011/viewspace-2695432/,如需轉載,請註明出處,否則將追究法律責任。

相關文章