1. 程式人生 > >【redis】叢集伸縮(新增刪除節點)

【redis】叢集伸縮(新增刪除節點)

注:本文知識點全部來自於《redis開發與運維》這本書在加上博主本人對於redis的理解構成

一、叢集伸縮原理

        Redis叢集提供了靈活的節點擴容和收縮方案。在不影響叢集對外服務的情況下,可以為叢集新增節點進行擴容也可以下線部分節點進行縮容:

我們都指導,這樣的每一個節點上面都分配了我們的16384槽中的幾個,以及對應槽下面的資料。所以我們在伸縮節點的時候,實質上也是對於雜湊槽和槽對應資料的一個調整。

首先我們先來看一下經典叢集搭建的分佈圖:

三個主節點分別維護自己負責的槽和對應的資料,如果希望加入1個節點實現叢集擴容時,需要通過相關命令把一部分槽和資料遷移給新節點:

總結:叢集伸縮就是槽和資料在節點之間移動。

二、叢集擴容

        我們的叢集在擴容的時候,是進行的增加節點的操作,故需要把已有節點上的槽和資料分配到新的節點上,那麼應該把已有節點上的哪些槽和節點放在新節點上呢?讓我們來探究。

      擴容是分散式儲存最常見的需求,Redis叢集擴容操作可分為如下步驟:

  1. 準備新節點。
  2. 加入叢集。
  3. 遷移槽和資料。

1.準備新節點

首先我們需要執行命令來啟動兩個新的redis節點:

redis-server conf/redis-6385.conf 
redis-server conf/redis-6386.conf

啟動之後,這兩個redis節點為孤立的節點

2、加入叢集

127.0.0.1:6379> cluster meet 127.0.0.1 6385 
127.0.0.1:6379> cluster meet 127.0.0.1 6386

執行上述命令加入已有的叢集。

        叢集內新舊節點經過一段時間的ping/pong訊息通訊之後,所有節點會發 現新節點並將它們的狀態儲存到本地。這個時間按照我們叢集的約定時間來確定。

        新節點剛開始都是主節點狀態,但是由於沒有負責的槽,所以不能接受任何讀寫操作。對於新節點的後續操作我們一般有兩種選擇:

  • 為它遷移槽和資料實現擴容。
  • 作為其他主節點的從節點負責故障轉移。

    redis-trib.rb工具也實現了為現有叢集新增新節點的命令,還實現了直接新增為從節點的支援,命令如下:

redis-trib.rb add-node new_host:new_port existing_host:existing_port --slave     --master-id <arg>

使用命令直接新增從節點:

redis-trib.rb add-node 127.0.0.1:6385 127.0.0.1:6379 
redis-trib.rb add-node 127.0.0.1:6386 127.0.0.1:6379

3、遷移槽和資料

         槽是Redis叢集管理資料的基本單位,首先需要為新節點制定槽的遷移計劃,確定原有節點的哪些槽需要遷移到新節點。遷移計劃需要確保每個節點負責相似數量的槽,從而保證各節點的資料均勻。例如,在叢集中加入 6385節點,如圖所示。加入6385節點後,原有節點負責的槽數量從 6380變為4096個。

槽遷移計劃確定後開始逐個把槽內資料從源節點遷移到目標節點。

遷移資料:

資料遷移過程是逐個槽進行的,流程如下:

1)對目標節點發送cluster setslot{slot}importing{sourceNodeId}命令,讓目標節點準備匯入槽的資料。 2)對源節點發送cluster setslot{slot}migrating{targetNodeId}命令,讓源節點準備遷出槽的資料。 3)源節點迴圈執行cluster getkeysinslot{slot}{count}命令,獲取count個 屬於槽{slot}的鍵。

   4)在源節點上執行migrate{targetIp}{targetPort}""0{timeout}keys{keys...} 命令,把獲取的鍵通過流水線(pipeline)機制批量遷移到目標節點,批量 遷移版本的migrate命令在Redis3.0.6以上版本提供,之前的migrate命令只能 單個鍵遷移。對於大量key的場景,批量鍵遷移將極大降低節點之間網路IO次數。    5)重複執行步驟3)和步驟4)直到槽下所有的鍵值資料遷移到目標節點。    6)向叢集內所有主節點發送cluster setslot{slot}node{targetNodeId}命令,通知槽分配給目標節點。為了保證槽節點對映變更及時傳播,需要遍歷傳送給所有主節點更新被遷移的槽指向新節點。

三、叢集收縮

        收縮叢集意味著縮減規模,需要從現有叢集中安全下線部分節點。

流程說明: 1)首先需要確定下線節點是否有負責的槽,如果是,需要把槽遷移到其他節點,保證節點下線後整個叢集槽節點對映的完整性。 2)當下線節點不再負責槽或者本身是從節點時,就可以通知叢集內其他節點忘記下線節點,當所有的節點忘記該節點後可以正常關閉。

1、下線遷移槽

      下線節點需要把自己負責的槽遷移到其他節點,原理與之前節點擴容的 遷移槽過程一致。例如我們把6381和6384節點下線,節點資訊如下:  

127.0.0.1:6381> cluster nodes 
40b8d09d44294d2e23c7c768efc8fcd153446746 127.0.0.1:6381 myself,master - 0 0 2 connected     
12288-16383 4fa7eac4080f0b667ffeab9b87841da49b84a6e4 127.0.0.1:6384 slave 
40b8d09d44294d2e2    3c7c768efc8fcd153446746 0 1469894180780 5 connected ...

6381是主節點,負責槽(12288-16383),6384是它的從節點,如圖所示。下線6381之前需要把負責的槽遷移到其他節點。

       收縮正好和擴容遷移方向相反,6381變為源節點,其他主節點變為目標 節點,源節點需要把自身負責的4096個槽均勻地遷移到其他主節點上。

我們可以使用用redis-trib.rb reshard命令完成槽的遷移:

#redis-trib.rb reshard 127.0.0.1:6381 
>>> Performing Cluster Check (using node 127.0.0.1:6381)
 ... 
[OK] All 16384 slots covered. 
How many slots do you want to move (from 1 to 16384)1365 
What is the receiving node ID cfb28ef1deee4e0fa78da86abe5d24566744411e /*輸入6379    
節點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. 
Source node #1:40b8d09d44294d2e23c7c768efc8fcd153446746 /*源節點6381 id*/ 
Source node #2:done /* 輸入done確認 */ 
... 
Do you want to proceed with the proposed reshard plan (yes/no) yes 
...

這樣完成了1365個槽往6379節點上面遷移,同樣的工作做三遍,即可遷移所有節點到其他節點上。

2、忘記節點

由於叢集內的節點不停地通過Gossip訊息彼此交換節點狀態,因此需要 通過一種健壯的機制讓叢集內所有節點忘記下線的節點。也就是說讓其他節 點不再與要下線節點進行Gossip訊息交換。Redis提供了cluster forget{downNodeId}命令實現該功能:

       當節點接收到cluster forget{down NodeId}命令後,會把nodeId指定的節 點加入到禁用列表中,在禁用列表內的節點不再發送Gossip訊息。禁用列表 有效期是60秒,超過60秒節點會再次參與訊息交換。也就是說當第一次 forget命令發出後,我們有60秒的時間讓叢集內的所有節點忘記下線節點。

       線上操作不建議直接使用cluster forget命令下線節點,需要跟大量節點 命令互動,實際操作起來過於繁瑣並且容易遺漏forget節點。建議使用redistrib.rb del-node{host:port}{downNodeId}命令。

redis-trib.rb del-node 127.0.0.1:6379 4fa7eac4080f0b667ffeab9b87841da49b84a6e4 # 從節點6384 id 
redis-trib.rb del-node 127.0.0.1:6379 40b8d09d44294d2e23c7c768efc8fcd153446746 # 主節點6381 id