redis cluster原始碼研究--reshard
reshard是redis cluster另一核心功能,它通過遷移雜湊槽來達到負載勻衡和可擴充套件目的。
使用者同樣可以用運維工具redis-trib.rb完成reshard工作,具體步驟如下:
(1)輸入如下命令:
./redis-trib.rb reshard 127.0.0.1:7000
其中127.0.0.1:7000是叢集裡任一節點。
(2)接著要求輸入需要遷移的雜湊槽數目,提示如下:
How many slots do you want to move (from 1 to 16384)?
假如輸入100
(3)接著要求輸入遷入雜湊槽的目的節點ID,提示如下:
What is the receiving node ID?
假如輸入ID:1
(4)接著要求輸入遷出雜湊槽的源節點ID,提示如下:
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
這裡可以輸入多個節點ID或選擇所有節點(all),這裡注意源節點ID不能是目的節點ID。
(5)接著redis-trib.rb會根據上面資訊制定遷移計劃,並輸出如下:
Resharding plan:
Moving slot $slot1 from $sourceid1
Moving slot $slot2 from $sourceid2
Do you want to proceed with the proposed reshard plan (yes/no)?
這裡輸入yes
(6)接著等待資料遷移完成,至此reshard工作結束。
二、實現原理
通過分析./redis-trib.rb reshard命令,上述(1)~(5)步驟都是在redis-trib.rb指令碼完成,到第(6)步才真正發命令給redis
cluster,前五步比較簡單理解,這裡就不分析了,下面主要分析第(6)步驟的實現。
第六步使用了個五叢集命令:cluster setslot imporing、cluster setslot migrating、cluster getkeysinslot、migrate和setslot node,下面對這四個命令進行分析:
(1)cluster setslot $slot imporing $sourceid
該命令是對target節點設定的,target節點收到該命令,會記錄該$slot有一個遷入源$sourceid,該節點在收到對該$slot的請求時會進行處理。
(2)cluster setslot $slot migrating $targetid
該命令是對source節點設定的,source節點收到該命令,會記錄該$slot有一個接收節點$targetid,該節點在處理對該$slot的請求時,如果發現key不在,則會回包給使用者,讓使用者重定用到$targetid。為什麼要重定向?這是因為在遷移slot過程中,一是要讓新的key寫入$targetid,二是正因為該slot的新key寫入$targetid,讀新key時也需要重定向到$targetid才能獲取新key資料。
(3)cluster getkeysinslot $slot $count
該命令是發給source節點的,目的是獲取該$slot的$count個keys。
(4)migrate $host $port $key $destination-db $timeout
該命令是發給source節點的,作用是原子地把$key原子地從source節點遷到target節點。通過(3)和(4)可以把該$slot所有keys遷到target節點。
(5)setslot $slot node $targetid
該命令是發給所有叢集節點,讓所有叢集節點更新該$slot的歸屬為$targetid,同時清除importing和migrating狀態,這裡因為會更新雜湊槽的歸屬,故target節點會更新epochconfig值,以保證其他節點更新為該epochconfig值的雜湊配置。
總結:
通過上面五個操作,就可以完美的遷移slot,遷移過程中不用停止redis cluster對外服務,只要使用者能處理重定向情況,就可以完全感知不到遷移slot。