xxl-job之負載均衡算法(四)

代碼全集

源碼回顧

調度中心觸發任務之後,他的調用鏈如下

RemoteHttpJobBean> executeInternal > XxlJobTrigger > trigger ,

通過之前的分析xxl-job 源碼解讀 (二) , 我們可以瞭解到,xxl-job他的路由策略主要發生在trigger這個方法中

上面的代碼主要講了分片廣播這個策略的實現以及xxl-job的其他路由策略的調用位置在哪裏。

ExecutorRouteStrategyEnum枚舉類

這個是xxl-job路由策略非常重要的一個類, 該類通過枚舉的方式,把路由key, 和策略實現類進行了一個聚合、

分片廣播

通過源碼回顧,我們可以清晰的看到,當系統判斷當前任務的路由策略是分片廣播時, 就會遍歷執行器的集羣機器列表,

給每一臺機器都發送執行消息,分片總數爲集羣機器數量,分片標記從0開始,上面的代碼已經非常清楚了,此處不再贅述。

第一個

由上面對ExecutorRouteStrategyEnum的分析,我們可以看到,該策略對應的是 這個ExecutorRouteFirst執行策略類。 主要看routeRun 這個方法

最後一個

直接 從執行機集羣列表的list裏面取最後一個,源碼如下

輪循

主要看ExecutorRouteRound這個類裏面的代碼

總結:這裏主要是通過一個ConcurrentHashMap來記錄每個任務對應的執行次數,維護一個count值, 通過這個count值 對集羣機器大小求於,得到list下標。

最終得到輪循的那臺機器。

問題: 既然次數是通過維護一個count值,通過list.get(count%size) 的這種方式獲取機器地址,爲啥要用求於的方式? 而不是用直接list.get(count)這種方式?

隨機

隨機這個策略比較簡單,通過在集羣列表的大小內隨機拿出一臺機器來執行,比較簡單,此處不再贅述

最不經常使用 (LFU)

單個JOB對應的每個執行器,使用頻率最低的優先被選舉

總結: 通過一個HashMap存儲每個任務對應的 機器執行次數,然後通過hashMap value排序, 得到執行次數最小的那個,也就是得到了最不經常使用的那臺機器

最近最久未使用(LRU)

單個JOB對應的每個執行器,最久爲使用的優先被選舉 , 此處使用的是linkedHashMap來實現LRU算法的。通過linkedHashMap的每次get/put的時候會進行排序,最新操作的數據會在最後面。 從而取第一個數據就代表是最久沒有被使用的

總結:此處主要是利用了LinkedHashMap的排序特性, get/put時都會對資源重排。 最久沒有被操作過的數據,就會排在前面。

一致性Hash

在講這個策略之前,先說一下一致性Hash算法 ,

先構造一個長度爲2^32的整數環(這個環被稱爲一致性Hash環),根據節點名稱的Hash值(其分佈爲[0, 2^32-1])將服務器節點放置在這個Hash環上,然後根據數據的Key值計算得到其Hash值(其分佈也爲[0, 2^32-1]),接着在Hash環上順時針查找距離這個Key值的Hash值最近的服務器節點,完成Key到服務器的映射查找。

 

 

 

例:

爲什麼需要一致性hash

比如你有 N 個 cache 服務器(後面簡稱 cache ),那麼如何將一個對象 object 映射到 N 個 cache 上呢,你很可能會採用通用的方法計算 object 的 hash 值,然後均勻的映射到到 N 個 cache ;hash(object)%N

一切都運行正常,再考慮如下的兩種情況;

1 一個 cache 服務器 m down 掉了(在實際應用中必須要考慮這種情況),這樣所有映射到 cache m 的對象都會失效,怎麼辦,需要把 cache m 從 cache 中移除,這時候 cache 是 N-1 臺,映射公式變成了 hash(object)%(N-1) ;

2 由於訪問加重,需要添加 cache ,這時候 cache 是 N+1 臺,映射公式變成了 hash(object)%(N+1) ;

1 和 2 意味着什麼?這意味着突然之間幾乎所有的 cache 都失效了。對於服務器而言,這是一場災難,洪水般的訪問都會直接衝向後臺服務器;

再來考慮第三個問題,由於硬件能力越來越強,你可能想讓後面添加的節點多做點活,顯然上面的 hash 算法也做不到。

有什麼方法可以改變這個狀況呢,這就是 consistent hashing…

源碼分析:

分組下機器地址相同,不同JOB均勻散列在不同機器上,保證分組下機器分配JOB平均;且每個JOB固定調度其中一臺機器;

這個地方使用的Hash方法是作者自己寫的,因爲String的hashCode可能重複,需要進一步擴大hashCode的取值範圍

題外擴展

問題:

 

添加節點D

 

 

添加節點D,但是節點D在A和B的中間,僅能分擔一點點的壓力,

所以需要引入虛擬節點的思想,解決一致性hash算法分佈不均導致負載不均的問題。一個真實節點對應若干個虛擬節點,當key被映射到虛擬節點上時,則被認爲映射到虛擬節點所對應的真實節點上。

例:

節點A: A1 , A2 , A3 , A4

節點B: B1 , B2 , B3 , B4

節點C: C1, C2, C3, C4

虛擬節點分散,假如A服務器宕機了,那麼A1,A2,A3,A4,虛擬節點失效,新來的請求會分散到服務器B,和服務器C一起分攤,解決了由於節點失效造成的負載不均的問題。

 

故障轉移

這個策略比較簡單,遍歷集羣地址列表,如果失敗,則繼續調用下一臺機器,成功則跳出循環,返回成功信息

忙碌轉移

這個策略更上面那個故障轉移的原理一致,只不過不同的是,故障轉移是判斷機器是否存活, 二忙碌轉移是想執行器發送消息判斷該任務對應的線程是否處於執行狀態。

看一下執行器那邊的idleBeat代碼實現

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章