Dubbo篇:負載均衡策略源碼分析



概述



???????在進行消費端服務調(diào)用的時候,看到初始化了LoadBalance,通過負載均衡獲取一個可用的節(jié)點。LoadBalance也是一個擴展點,Dubbo內(nèi)置了4種負載均衡算法,
都繼承自AbstractLoadBalance,AbstractLoadBalance中實現(xiàn)通用邏輯,留一個抽象方法doSelect方法給子類實現(xiàn),默認是RandomLoadBalance實現(xiàn)。四個負載均衡實現(xiàn)子類如下:

?????????????RandomLoadBalance:隨機,按權(quán)重設置隨機概率。在一個截面上碰撞的概率高,但調(diào)用量越大分布越均勻,而且按概率使用權(quán)重后也比較均勻,有利于動態(tài)調(diào)整提供者的權(quán)重。

?????????????RoundRobinLoadBalance:輪詢,按公約后的權(quán)重設置輪詢比例。存在慢的提供者累計請求的問題,比如:第二天機器很慢,但沒“掛”,當請求調(diào)到第二臺時就卡在那里,久而久之,所以請求都卡在調(diào)到第二臺上。

?????????????LeastActiveLoadBalance:最少活躍調(diào)用數(shù),如果活躍數(shù)相同則隨機調(diào)用,活躍數(shù)指調(diào)用前后計數(shù)差。使慢的提供者收到更少請求,因為越慢的提供者的調(diào)用前后計數(shù)差會越大。

?????????????ConsistentHashLoadBalance:一致性Hash,相同參數(shù)的請求總是發(fā)到同一提供者。當某一臺提供者“掛”是,原本發(fā)往該提供者的請求,基于虛擬節(jié)點,會平攤到其他提供者,不會引起劇烈變動。默認只對第一個參數(shù)“Hash”,默認使用160份虛擬節(jié)點。



AbstractLoadBalance



???????AbstractLoadBalance實現(xiàn)較為簡單,提供了一個select方法調(diào)用子類重寫的doSelect方法,提供了getWeight用于計算權(quán)重,代碼實現(xiàn)如下:

在這里插入圖片描述

???????getWeight獲取當前權(quán)重,其中調(diào)用了calculateWarmupWeight,主要實現(xiàn)了獲取權(quán)重的時的預熱,服務啟動是并不會直接給予100%的流量,計算邏輯是:(啟動至今時間 / 給予的預熱總時間)* 權(quán)重。



Random負載均衡



???????RandomLoadBalance按照權(quán)重設置隨機概率做負載均衡,這種算法并不能精確地做平均請求,但是隨著請求數(shù)量的增加,最終結(jié)果大致平均,代碼實現(xiàn)如下:

在這里插入圖片描述

???????時間比較簡單,如果權(quán)重都一樣,則直接隨機返回一個,如果權(quán)重不一樣,則把每個Invoker的權(quán)重看作一個區(qū)間,以總權(quán)重為基礎獲取一個隨機數(shù),然后用隨機數(shù)依次減去每個權(quán)重,當隨機數(shù)小于零的時候結(jié)束,即看這個隨機數(shù)落在哪個invoker的權(quán)重區(qū)間中,就返回這個invoker。



RoundRobin負載均衡



???????RoundRobin負載均衡算法的實現(xiàn)為平滑權(quán)重輪詢算法。在輪詢的基礎上加上了負載均衡的算法。實現(xiàn)代碼如下:

在這里插入圖片描述

???????算法邏輯是每次請求做負載均衡時,會遍歷所有Invoker節(jié)點,對于每個Invoker,會讓它的current = current + weight。同時會把每個Invoker的weight累加到totalWeight總權(quán)重,即totalWeight = totalWeight + weight。遍歷完成后會保存current值最大的就是本次要返回的節(jié)點,返回前會將其current減去totalWeight,即current = current - totalWeight,現(xiàn)在選擇的時候會在現(xiàn)有的current值上基礎上再做上次操作,將totalWeight置0,重復上述邏輯。選中過的Invoker的current值會因為減去了totalWeight,所以最小,再次選中它的話就要等根據(jù)自身權(quán)重一次一次加成最大,因此權(quán)重大的就更快的再次被選中,權(quán)重小的就慢些被再次被選中,而且不也會一直調(diào)用權(quán)重大的Invoker,會有權(quán)重小的穿插進去。



LeastActive負載均衡



???????LeastActive負載均衡是最小活躍調(diào)用數(shù)負載均衡,框架會記下每個Invoker的活躍數(shù),每次只從活躍數(shù)最小的Invoker里選一個節(jié)點。這個負載均衡算法需要配合ActiveLimitFilter過濾器來計算每個接口方法的活躍數(shù)。LeastActiveLoadBalance代碼實現(xiàn)如下:

在這里插入圖片描述

???????其實現(xiàn)邏輯較為簡單,遍歷invoker列表,找出其所有活躍數(shù)最小的invoker,保存到一個集合中,然后用Random負載均衡方式從中選出一個Invoker。



一致性Hash負載均衡



???????一致性Hash負載均衡可以讓參數(shù)相同的請求每次都路由到相同的機器上。這種負載均衡的方式可以然后請求相對平均,當某些節(jié)點下線時,請求會平攤到其他服務者,不會引起劇烈的變動。Dubbo框架使用了優(yōu)化過Ketama一致性Hash,這種算法會為每個節(jié)點在創(chuàng)建多個虛擬節(jié)點,讓節(jié)點在環(huán)形上的分布更均勻,后續(xù)的調(diào)用也會隨之更加均勻。ConsistentHashLoadBalance代碼實現(xiàn)如下:

在這里插入圖片描述

???????邏輯核心在ConsistentHashSelector中,ConsistentHashSelector初始化時會對節(jié)點進行散列,散列的環(huán)形使用一個TreeMap實現(xiàn),所有的真實、虛擬的節(jié)點都會放入TreeMap。把節(jié)點的IP+遞增數(shù)字做“MD5”,以此作為節(jié)點標識,再對標識做hash得到TreeMap的key,最后把可以調(diào)用的節(jié)點作為TreeMap的value。在客戶端調(diào)用的時候,只要對請求的參數(shù)也做MD5即可,雖然此時得到的MD5之不一定能對應到TreeMap的key,因為每次請求的參數(shù)不一樣,以為TreeMap是有序樹形結(jié)構(gòu),可以調(diào)用TreeMap的ceilingEntry方法,用于返回一個至少大于或等于當前給定key的Entry,從而達到順時針往前找的效果。如果找不到,則使用firstEntry返回第一個節(jié)點。



參考:

《深入理解 Apache Dubbo與實戰(zhàn)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容