Dubbo?LoadBalance基于權(quán)重的隨機(jī)負(fù)載均衡算法提高服務(wù)性能
導(dǎo)讀
Dubbo是一個(gè)分布式服務(wù)框架,能避免單點(diǎn)故障和支持服務(wù)的橫向擴(kuò)容。一個(gè)服務(wù)通常會(huì)部署多個(gè)實(shí)例。如何從多個(gè)服務(wù) Provider 組成的集群中挑選出一個(gè)進(jìn)行調(diào)用,就涉及到一個(gè)負(fù)載均衡的策略。
負(fù)載均衡職責(zé)是將網(wǎng)絡(luò)請(qǐng)求或者其他形式的負(fù)載“均攤”到不同的服務(wù)節(jié)點(diǎn)上,從而避免服務(wù)集群中部分節(jié)點(diǎn)壓力過大、資源緊張,而另一部分節(jié)點(diǎn)比較空閑的情況。通過合理的負(fù)載均衡算法,我們希望可以讓每個(gè)服務(wù)節(jié)點(diǎn)獲取到適合自己處理能力的負(fù)載,實(shí)現(xiàn)處理能力和流量的合理分配。常用的負(fù)載均衡可分為軟件負(fù)載均衡(比如,日常工作中使用的 Nginx)和硬件負(fù)載均衡(主要有 F5、Array、NetScaler 等,不過開發(fā)工程師在實(shí)踐中很少直接接觸到)。
Dubbo提供了 5 種負(fù)載均衡實(shí)現(xiàn)
- 基于 Hash 一致性的 ConsistentHashLoadBalance;
- 基于權(quán)重隨機(jī)算法的 RandomLoadBalance;
- 基于最少活躍調(diào)用數(shù)算法的 LeastActiveLoadBalance;
- 基于加權(quán)輪詢算法的 RoundRobinLoadBalance;
- 基于最短響應(yīng)時(shí)間的 ShortestResponseLoadBalance 。
LoadBalance 是一個(gè)擴(kuò)展接口,默認(rèn)使用的擴(kuò)展實(shí)現(xiàn)是 RandomLoadBalance,其定義如下所示,其中的 @Adaptive 注解參數(shù)為 loadbalance,即動(dòng)態(tài)生成的適配器會(huì)按照 URL 中的 loadbalance 參數(shù)值選擇擴(kuò)展實(shí)現(xiàn)類。
@SPI(RandomLoadBalance.NAME) public interface LoadBalance { @Adaptive("loadbalance") <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException; }
LoadBalance 接口中 select() 方法的核心功能是根據(jù)傳入的 URL 和 Invocation,以及自身的負(fù)載均衡算法,從 Invoker 集合中選擇一個(gè) Invoker 返回。
ConsistentHashLoadBalance(一致性 Hash算法)
底層使用一致性 Hash 算法實(shí)現(xiàn)負(fù)載均衡。
一致性 Hash 負(fù)載均衡可以讓參數(shù)相同的請(qǐng)求每次都路由到相同的服務(wù)節(jié)點(diǎn)上,這種負(fù)載均衡策略可以在某些 Provider 節(jié)點(diǎn)下線的時(shí)候,讓這些節(jié)點(diǎn)上的流量平攤到其他 Provider 上,不會(huì)引起流量的劇烈波動(dòng)。
假設(shè)現(xiàn)在有 1、2、3 三個(gè) Provider 節(jié)點(diǎn)對(duì)外提供服務(wù),有 100 個(gè)請(qǐng)求同時(shí)到達(dá),如果想讓請(qǐng)求盡可能均勻地分布到這三個(gè) Provider 節(jié)點(diǎn)上,我們可能想到的最簡單的方法就是 Hash 取模,即 hash(請(qǐng)求參數(shù)) % 3。如果參與 Hash 計(jì)算的是請(qǐng)求的全部參數(shù),那么參數(shù)相同的請(qǐng)求將會(huì)落到同一個(gè) Provider 節(jié)點(diǎn)上。不過此時(shí)如果突然有一個(gè) Provider 節(jié)點(diǎn)出現(xiàn)宕機(jī)的情況,那我們就需要對(duì) 2 取模,即請(qǐng)求會(huì)重新分配到相應(yīng)的 Provider 之上。在極端情況下,甚至?xí)霈F(xiàn)所有請(qǐng)求的處理節(jié)點(diǎn)都發(fā)生了變化,這就會(huì)造成比較大的波動(dòng)。
為了避免因一個(gè) Provider 節(jié)點(diǎn)宕機(jī),而導(dǎo)致大量請(qǐng)求的處理節(jié)點(diǎn)發(fā)生變化的情況,我們可以考慮使用一致性 Hash 算法。一致性 Hash 算法的原理也是取模算法,與 Hash 取模的不同之處在于:Hash 取模是對(duì) Provider 節(jié)點(diǎn)數(shù)量取模,而一致性 Hash 算法是對(duì) 2^32 取模。
一致性 Hash 算法需要同時(shí)對(duì) Provider 地址以及請(qǐng)求參數(shù)進(jìn)行取模:
hash(Provider地址) % 2^32
hash(請(qǐng)求參數(shù)) % 2^32
Provider 地址和請(qǐng)求經(jīng)過對(duì) 2^32 取模得到的結(jié)果值,都會(huì)落到一個(gè) Hash 環(huán)上.
一致性 Hash節(jié)點(diǎn)均勻分布
我們按順時(shí)針的方向,依次將請(qǐng)求分發(fā)到對(duì)應(yīng)的 Provider。這樣,當(dāng)某臺(tái) Provider 節(jié)點(diǎn)宕機(jī)或增加新的 Provider 節(jié)點(diǎn)時(shí),只會(huì)影響這個(gè) Provider 節(jié)點(diǎn)對(duì)應(yīng)的請(qǐng)求。
在理想情況下,一致性 Hash 算法會(huì)將這三個(gè) Provider 節(jié)點(diǎn)均勻地分布到 Hash 環(huán)上,請(qǐng)求也可以均勻地分發(fā)給這三個(gè) Provider 節(jié)點(diǎn)。但在實(shí)際情況中,這三個(gè) Provider 節(jié)點(diǎn)地址取模之后的值,可能差距不大,這樣會(huì)導(dǎo)致大量的請(qǐng)求落到一個(gè) Provider 節(jié)點(diǎn)上。就出現(xiàn)了數(shù)據(jù)傾斜的問題。所謂數(shù)據(jù)傾斜是指由于節(jié)點(diǎn)不夠分散,導(dǎo)致大量請(qǐng)求落到了同一個(gè)節(jié)點(diǎn)上,而其他節(jié)點(diǎn)只會(huì)接收到少量請(qǐng)求的情況。
為了解決一致性 Hash 算法中出現(xiàn)的數(shù)據(jù)傾斜問題,又演化出了 Hash 槽的概念。
Hash 槽解決數(shù)據(jù)傾斜的思路是:既然問題是由 Provider 節(jié)點(diǎn)在 Hash 環(huán)上分布不均勻造成的,那么可以虛擬出 n 組 P1、P2、P3 的 Provider 節(jié)點(diǎn) ,讓多組 Provider 節(jié)點(diǎn)相對(duì)均勻地分布在 Hash 環(huán)上。如下圖所示,相同陰影的節(jié)點(diǎn)均為同一個(gè) Provider 節(jié)點(diǎn),比如 P1-1、P1-2……P1-99 表示的都是 P1 這個(gè) Provider 節(jié)點(diǎn)。引入 Provider 虛擬節(jié)點(diǎn)之后,讓 Provider 在圓環(huán)上分散開來,以避免數(shù)據(jù)傾斜問題。
RandomLoadBalance(加權(quán)隨機(jī)算法)
RandomLoadBalance 是一個(gè)簡單、高效的負(fù)載均衡實(shí)現(xiàn),它也是 Dubbo 默認(rèn)使用的 LoadBalance 實(shí)現(xiàn)。
下面我們通過隨機(jī)數(shù)生成器在 [0, 10) 這個(gè)范圍內(nèi)生成一個(gè)隨機(jī)數(shù),然后計(jì)算這個(gè)隨機(jī)數(shù)會(huì)落到哪個(gè)區(qū)間中。例如,隨機(jī)生成 4,就會(huì)落到 Provider A 對(duì)應(yīng)的區(qū)間中,此時(shí) RandomLoadBalance 就會(huì)返回 Provider A 這個(gè)節(jié)點(diǎn)。
接下來我們?cè)賮砜?RandomLoadBalance 中 doSelect() 方法的實(shí)現(xiàn),其核心邏輯為三個(gè)關(guān)鍵點(diǎn):
- 計(jì)算每個(gè) Invoker 對(duì)應(yīng)的權(quán)重值以及總權(quán)重值;
- 當(dāng)各個(gè) Invoker 權(quán)重值不相等時(shí),計(jì)算隨機(jī)數(shù)應(yīng)該落在哪個(gè) Invoker 區(qū)間中,返回對(duì)應(yīng)的 Invoker 對(duì)象;
- 當(dāng)各個(gè) Invoker 權(quán)重值相同時(shí),隨機(jī)返回一個(gè) Invoker 即可。
RandomLoadBalance 經(jīng)過多次請(qǐng)求后,能夠?qū)⒄{(diào)用請(qǐng)求按照權(quán)重值均勻地分配到各個(gè) Provider 節(jié)點(diǎn)上。
LeastActiveLoadBalance(最小活躍數(shù)負(fù)載均衡算法)
LeastActiveLoadBalance 使用的是最小活躍數(shù)負(fù)載均衡算法。它認(rèn)為當(dāng)前活躍請(qǐng)求數(shù)越小的 Provider 節(jié)點(diǎn),剩余的處理能力越多,處理請(qǐng)求的效率也就越高,那么該 Provider 在單位時(shí)間內(nèi)就可以處理更多的請(qǐng)求,所以我們應(yīng)該優(yōu)先將請(qǐng)求分配給該 Provider 節(jié)點(diǎn)。
LeastActiveLoadBalance 需要配合 ActiveLimitFilter 使用,ActiveLimitFilter 會(huì)記錄每個(gè)接口方法的活躍請(qǐng)求數(shù),在 LeastActiveLoadBalance 進(jìn)行負(fù)載均衡時(shí),只會(huì)從活躍請(qǐng)求數(shù)最少的 Invoker 集合里挑選 Invoker。
在 LeastActiveLoadBalance 的實(shí)現(xiàn)中,首先會(huì)選出所有活躍請(qǐng)求數(shù)最小的 Invoker 對(duì)象,之后的邏輯與RandomLoadBalance 完全一樣,按照這些 Invoker 對(duì)象的權(quán)重挑選最終的Invoker 對(duì)象。
RoundRobinLoadBalance(加權(quán)輪詢負(fù)載均衡算法)
輪詢指的是將請(qǐng)求輪流分配給每個(gè) Provider。例如,有 A、B、C 三個(gè) Provider 節(jié)點(diǎn),按照普通輪詢的方式,我們會(huì)將第一個(gè)請(qǐng)求分配給 Provider A,將第二個(gè)請(qǐng)求分配給 Provider B,第三個(gè)請(qǐng)求分配給 Provider C,第四個(gè)請(qǐng)求再次分配給 Provider A……如此循環(huán)往復(fù)。
輪詢是一種無狀態(tài)負(fù)載均衡算法,實(shí)現(xiàn)簡單,適用于集群中所有 Provider 節(jié)點(diǎn)性能相近的場景。 但現(xiàn)實(shí)情況中就很難保證這一點(diǎn)了,因?yàn)楹苋菀壮霈F(xiàn)集群中性能最好和最差的 Provider 節(jié)點(diǎn)處理同樣流量的情況,這就可能導(dǎo)致性能差的 Provider 節(jié)點(diǎn)各方面資源非常緊張,甚至無法及時(shí)響應(yīng)了,但是性能好的 Provider 節(jié)點(diǎn)的各方面資源使用還較為空閑。這時(shí)我們可以通過加權(quán)輪詢的方式,降低分配到性能較差的 Provider 節(jié)點(diǎn)的流量。
加權(quán)之后,分配給每個(gè) Provider 節(jié)點(diǎn)的流量比會(huì)接近或等于它們的權(quán)重比。例如,Provider 節(jié)點(diǎn) A、B、C 權(quán)重比為 5:1:1,那么在 7 次請(qǐng)求中,節(jié)點(diǎn) A 將收到 5 次請(qǐng)求,節(jié)點(diǎn) B 會(huì)收到 1 次請(qǐng)求,節(jié)點(diǎn) C 則會(huì)收到 1 次請(qǐng)求。
ShortestResponseLoadBalance(最短響應(yīng)時(shí)間的負(fù)載均衡算法)
ShortestResponseLoadBalance 是Dubbo 2.7 版本之后新增加的一個(gè) LoadBalance 實(shí)現(xiàn)類。它實(shí)現(xiàn)了最短響應(yīng)時(shí)間的負(fù)載均衡算法,也就是從多個(gè) Provider 節(jié)點(diǎn)中選出調(diào)用成功的且響應(yīng)時(shí)間最短的 Provider 節(jié)點(diǎn),不過滿足該條件的 Provider 節(jié)點(diǎn)可能有多個(gè),所以還要再使用隨機(jī)算法進(jìn)行一次選擇,得到最終要調(diào)用的 Provider 節(jié)點(diǎn)。
以上就是Dubbo的負(fù)載均衡(LoadBalance)原理的詳細(xì)內(nèi)容,更多關(guān)于Dubbo 負(fù)載均衡的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java設(shè)計(jì)模式之觀察者模式observer?pattern詳解
這篇文章主要介紹了Java設(shè)計(jì)模式之觀察者模式observer?pattern詳解,當(dāng)一個(gè)對(duì)象發(fā)生數(shù)據(jù)變化時(shí),通知其他相關(guān)的一系列對(duì)象,接受到通知的對(duì)象根據(jù)該對(duì)象的變化進(jìn)行相應(yīng)處理以響應(yīng)變化的過程,需要的朋友可以參考下2023-12-12spring mvc 和ajax異步交互完整實(shí)例代碼
本篇文章主要介紹了spring mvc 和ajax異步交互完整實(shí)例代碼,簡單的AJAX+SpringMVC的異步交互小例子,有興趣的可以了解一下。2017-02-02Spring Security實(shí)現(xiàn)兩周內(nèi)自動(dòng)登錄"記住我"功能
登錄過程中經(jīng)常使用的“記住我”功能,也就是我們經(jīng)常會(huì)在各種網(wǎng)站登陸時(shí)見到的"兩周內(nèi)免登錄",“三天內(nèi)免登錄”的功能。今天小編給大家分享基于Spring Security實(shí)現(xiàn)兩周內(nèi)自動(dòng)登錄"記住我"功能,感興趣的朋友一起看看吧2019-11-11java實(shí)現(xiàn)上傳圖片尺寸修改和質(zhì)量壓縮
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)上傳圖片尺寸修改和質(zhì)量壓縮,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04Java EE項(xiàng)目中的異常處理總結(jié)(一篇不得不看的文章)
什么是異常?運(yùn)行時(shí)發(fā)生的可被捕獲和處理的錯(cuò)誤。這篇文章主要介紹了Java EE項(xiàng)目中的異常處理總結(jié),有需要的可以了解一下。2016-11-11java開發(fā)MyBatis中常用plus實(shí)體類注解符詳解
這篇文章主要為大家介紹了java開發(fā)MyBatis常用的plus實(shí)體類注解符示例應(yīng)用詳解有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10詳解java中this.getClass()和super.getClass()的實(shí)例
這篇文章主要介紹了詳解java中this.getClass()和super.getClass()的實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-08-08