Redis Cluster 集群擴容與收縮


 

http://blog.csdn.net/men_wen/article/details/72896682

 

 

Redis 學習筆記(十五)Redis Cluster 集群擴容與收縮

標簽: redis集群博客通信源碼
分類:

目錄(?)[+]

Redis Cluster 集群伸縮

1. 伸縮原理

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

我們在Redis Cluster 介紹與搭建這篇文章中搭建了一個三主三從Redis集群(如下圖所示)。在搭建 Redis Cluster 通信流程剖析這篇博客中根據源碼詳細剖析了搭建集群的流程。

這里寫圖片描述

本篇博客要講的是,Redis集群的擴容和縮容過程。

我們先根據Redis Cluster 介紹與搭建將如圖的集群搭建起來,查看搭建的效果。

127.0.0.1:6379> cluster nodes 29978c0169ecc0a9054de7f4142155c1ab70258b 127.0.0.1:6379 myself,master - 0 0 7 connected 0-5461 8f285670923d4f1c599ecc93367c95a30fb8bf34 127.0.0.1:6380 master - 0 1496717082785 3 connected 5462-10922 66478bda726ae6ba4e8fb55034d8e5e5804223ff 127.0.0.1:6381 master - 0 1496717085793 2 connected 10923-16383 961097d6be64ebd2fd739ff719e97565a8cee7b5 127.0.0.1:6382 slave 29978c0169ecc0a9054de7f4142155c1ab70258b 0 1496717084791 7 connected 6fb7dfdb6188a9fe53c48ea32d541724f36434e9 127.0.0.1:6383 slave 8f285670923d4f1c599ecc93367c95a30fb8bf34 0 1496717087797 4 connected e0c7961a1b07ab655bc31d8dfd583da565ec167d 127.0.0.1:6384 slave 66478bda726ae6ba4e8fb55034d8e5e5804223ff 0 1496717086795 2 connected
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

對應的主節點負責的槽位信息,如下圖所示:

這里寫圖片描述

2. 擴容集群

擴容集群是分布式存儲最常見的需求,Redis集群擴容可以分為如下步驟:

  • 准備新節點
  • 加入集群
  • 遷移槽和數據

2.1 准備新節點

我們需要兩個節點,端口分別為63856386,配置和之前集群節點配置基本相同,除了端口不同,以便於管理。6385節點配置如下:

port 6385 //端口 cluster-enabled yes //開啟集群模式 cluster-config-file nodes-6385.conf //集群內部的配置文件 cluster-node-timeout 15000 //節點超時時間,單位毫秒 // 其他配置和單機模式相同
  • 1
  • 2
  • 3
  • 4
  • 5

啟動兩個節點

sudo redis-server conf/redis-6385.conf sudo redis-server conf/redis-6386.conf
  • 1
  • 2

啟動后的新節點會作為孤兒節點運行,沒有和其他節點與之通信。

2.2 加入集群

我們可以通過CLUSTER MEET命令將6385節點加入到集群中。

127.0.0.1:6379> CLUSTER MEET 127.0.0.1 6385 OK 127.0.0.1:6379> CLUSTER NODES cb987394a3acc7a5e606c72e61174b48e437cedb 127.0.0.1:6385 master - 0 1496731333689 8 connected ......
  • 1
  • 2
  • 3
  • 4
  • 5

也可以使用redis專門進行集群管理的工具redis-trib.rb,位於Redis的源碼目錄中,把6386節點加入到集群中

sudo src/redis-trib.rb add-node 127.0.0.1:6386 127.0.0.1:6379 127.0.0.1:6379> CLUSTER NODES cdfb1656353c5c7f29d0330a754c71d53cec464c 127.0.0.1:6386 master - 0 1496731447703 0 connected ......
  • 1
  • 2
  • 3
  • 4

這兩種方法可以,新加入的節點都是主節點,因為沒有負責槽位,所以不能接受任何讀寫操作,對於新加入的節點,我們可以有兩個操作:

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

2.3 遷移槽和數據

當我們將新節點加入集群后,我們就可以將槽和數據遷移到新的節點,遷移的方法也有兩種,可以使用redis-trib.rb工具,也可以通過手動命令的方式,但是一般要確保每個主節點負責的槽數是均勻的,因此要使用redis-trib.rb工具來批量完成,但是我們只是為了演示遷移的過程,所以接下來手動使用命令進行遷移。

我們先創建幾個屬於一個槽的鍵,將這些鍵遷移到新的節點中。

127.0.0.1:6379> SET key:{test}:555 value:test:555 -> Redirected to slot [6918] located at 127.0.0.1:6380 OK 127.0.0.1:6380> SET key:{test}:666 value:test:666 OK 127.0.0.1:6380> SET key:{test}:777 value:test:777 OK 127.0.0.1:6380> CLUSTER KEYSLOT key:{test}:555 (integer) 6918 127.0.0.1:6380> CLUSTER KEYSLOT key:{test}:666 (integer) 6918 127.0.0.1:6380> CLUSTER KEYSLOT key:{test}:777 (integer) 6918
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

本來在6379節點中創建,但是重定向到了6380節點中,因為我們常見的鍵根據CRC16算法計算分配到了6918槽中,而這個槽由6380節點負責。

如果鍵的名字中帶有{},那么計算哈希值時就只計算{}包含的字符串,所以創建的三個鍵屬於一個槽。

計算哈希值的源碼如下:

unsigned int keyHashSlot(char *key, int keylen) { int s, e; /* start-end indexes of { and } */ // 找'{'字符 for (s = 0; s < keylen; s++) if (key[s] == '{') break; // 沒有找到"{}",直接計算整個key的哈希值 if (s == keylen) return crc16(key,keylen) & 0x3FFF; // 找到'{',檢查是否有'}' for (e = s+1; e < keylen; e++) if (key[e] == '}') break; // 沒有找到配對的'}',直接計算整個key的哈希值 if (e == keylen || e == s+1) return crc16(key,keylen) & 0x3FFF; // 如果找到了"{}",計算{}中間的哈希值 return crc16(key+s+1,e-s-1) & 0x3FFF; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

我們已經獲取了要遷移的槽,是6918。因此,流程如下:

  • 目標6385節點中,將槽6918設置為導入狀態
127.0.0.1:6385> CLUSTER SETSLOT 6918 importing 8f285670923d4f1c599ecc93367c95a30fb8bf34 OK // 8f285670923d4f1c599ecc93367c95a30fb8bf34 是 6380 節點的名字
  • 1
  • 2
  • 3

目標6385節點中,查看槽6918導入狀態

127.0.0.1:6385> CLUSTER NODES cb987394a3acc7a5e606c72e61174b48e437cedb 127.0.0.1:6385 myself,master - 0 0 8 connected [6918-<-8f285670923d4f1c599ecc93367c95a30fb8bf34]
  • 1
  • 2
  • 6380節點中,將槽6918設置為導出狀態
127.0.0.1:6380> CLUSTER SETSLOT 6918 migrating cb987394a3acc7a5e606c72e61174b48e437cedb OK // cb987394a3acc7a5e606c72e61174b48e437cedb 是 6385 節點的名字
  • 1
  • 2
  • 3

6380節點中,查看槽6918導出狀態

127.0.0.1:6380> CLUSTER NODES 8f285670923d4f1c599ecc93367c95a30fb8bf34 127.0.0.1:6380 myself,master - 0 0 3 connected 5462-10922 [6918->-cb987394a3acc7a5e606c72e61174b48e437cedb]
  • 1
  • 2
  • 批量獲取槽6918中的鍵
127.0.0.1:6380> CLUSTER GETKEYSINSLOT 6918 5 1) "key:{test}:555" 2) "key:{test}:666" 3) "key:{test}:777"
  • 1
  • 2
  • 3
  • 4

確認一下這三個鍵是否存在於源6380節點。

127.0.0.1:6380> MGET key:{test}:777 key:{test}:666 key:{test}:555 1) "value:test:777" 2) "value:test:666" 3) "value:test:555"
  • 1
  • 2
  • 3
  • 4
  • 執行migrate命令進行遷移
127.0.0.1:6380> MIGRATE 127.0.0.1 6385 "" 0 1000 keys key:{test}:777 key:{test}:666 key:{test}:555 OK
  • 1
  • 2

批量遷移版本的MIGRATE命令是在redis 3.0.6之后加入的,命令參數如下:

MIGRATE host port key dbid timeout [COPY | REPLACE]
MIGRATE host port "" dbid timeout [COPY | REPLACE] KEYS key1 key2 ... keyN // host port 指定遷移的目的節點地址 // dbid 指定遷移的數據庫id // timeout 遷移的超時時間 // 如果指定了 COPY 選項,表示不刪除源節點上的key // 如果指定了 REPLACE 選項,替換目標節點上已存在的key(如果存在)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

當遷移完成后,我們在源6380節點查詢這三個鍵,發送回復了一個ASK錯誤

127.0.0.1:6380> MGET key:{test}:777 key:{test}:666 key:{test}:555 (error) ASK 6918 127.0.0.1:6385
  • 1
  • 2

最后,我們只需向任意節點發送CLUSTER SETSLOT <slot> NODE <target_name>命令,將槽指派的信息發送給節點,然后這個節點會將這個指派信息發送至整個集群。

CLUSTER SETSLOT 6918 node cb987394a3acc7a5e606c72e61174b48e437cedb // cb987394a3acc7a5e606c72e61174b48e437cedb 是 6385 節點的名字
  • 1
  • 2

6381節點執行命令

127.0.0.1:6381> CLUSTER SETSLOT 6918 node cb987394a3acc7a5e606c72e61174b48e437cedb OK
  • 1
  • 2

6379節點查看當前集群槽指派信息

127.0.0.1:6379> CLUSTER NODES 29978c0169ecc0a9054de7f4142155c1ab70258b 127.0.0.1:6379 myself,master - 0 0 7 connected 0-5461 66478bda726ae6ba4e8fb55034d8e5e5804223ff 127.0.0.1:6381 master - 0 1496736248776 2 connected 10923-16383 cb987394a3acc7a5e606c72e61174b48e437cedb 127.0.0.1:6385 master - 0 1496736244766 10 connected 6918 8f285670923d4f1c599ecc93367c95a30fb8bf34 127.0.0.1:6380 master - 0 1496736247773 3 connected 5462-6917 6919-10922 // 過濾掉從節點和未指派槽的主節點
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以看到6380節點負責的槽變為5462-6917 6919-10922,而6918已經被6385節點負責了。

  • 添加從節點

開始的時候,我們加入了兩個新節點到集群中,節點6385已經遷移了槽位和數據作為主節點,但是該節點還不具有故障轉移的能力。

此時,還需要將6386節點作為6385節點的從節點,從而保證集群的高可用。使用cluster replicate <master_id>命令為主節點添加從節點,集群模式下不支持slaveof命令。

127.0.0.1:6386> CLUSTER REPLICATE cb987394a3acc7a5e606c72e61174b48e437cedb OK 127.0.0.1:6386> CLUSTER NODES cb987394a3acc7a5e606c72e61174b48e437cedb 127.0.0.1:6385 master - 0 1496742992748 10 connected 6918 cdfb1656353c5c7f29d0330a754c71d53cec464c 127.0.0.1:6386 myself,slave cb987394a3acc7a5e606c72e61174b48e437cedb 0 0 0 connected
  • 1
  • 2
  • 3
  • 4
  • 5

到此就完成了集群的擴容。集群關系如下圖所示:

這里寫圖片描述

3. 收縮集群

收縮集群以為着縮減規模,需要從集群中安全下線部分節點。需要考慮兩種情況:

  • 確定下線的節點是否有負責槽,如果是,需要把槽遷移到其他節點,保證節點下線后整個槽節點映射的完整性。
  • 當下線節點不在負責槽或着本身是從節點時,就可以通知集群內其他節點忘記下線節點,當所有節點忘記該節點后就可以正常關閉。

我們這次使用redis-trib.rb工具來下線遷移槽。流程和擴容集群非常相似,正好方向相反,將6380變為目標節點,6385成了源節點。將剛才新擴容的集群收縮回去。

./redis-trib.rb reshard 127.0.0.1:6385 >>> Performing Cluster Check (using node 127.0.0.1:6385) ...... [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. // 你想遷移多少個槽 How many slots do you want to move (from 1 to 16384)? 1 /*遷移一個槽*/ // 目標節點的id What is the receiving node ID? 8f285670923d4f1c599ecc93367c95a30fb8bf34 /*輸入目標`6380`節點的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. // 輸入要遷移槽的源節點 // all 表示所有節點都是源節點 // done 表示輸入完成 Source node #1:cb987394a3acc7a5e606c72e61174b48e437cedb Source node #2:done ..... // 是否立即執行重新分片計划 Do you want to proceed with the proposed reshard plan (yes/no)? yes Moving slot 6918 from 127.0.0.1:6385 to 127.0.0.1:6380: ...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

查看一下結果:

127.0.0.1:6380> CLUSTER NODES 8f285670923d4f1c599ecc93367c95a30fb8bf34 127.0.0.1:6380 myself,master - 0 0 11 connected 5462-10922 cb987394a3acc7a5e606c72e61174b48e437cedb 127.0.0.1:6385 master - 0 1496744498017 10 connected
  • 1
  • 2
  • 3

6380節點已經接管了6385節點的槽。

最后讓集群所有的節點忘記下線節點6385。執行CLUSTER FORGET <down_node_id>或者使用工具。

./redis-trib.rb del-node 127.0.0.1:6379 cdfb1656353c5c7f29d0330a754c71d53cec464c >>> Removing node cdfb1656353c5c7f29d0330a754c71d53cec464c from cluster 127.0.0.1:6379 >>> Sending CLUSTER FORGET messages to the cluster... >>> SHUTDOWN the node. ./redis-trib.rb del-node 127.0.0.1:6379 cb987394a3acc7a5e606c72e61174b48e437cedb >>> Removing node cb987394a3acc7a5e606c72e61174b48e437cedb from cluster 127.0.0.1:6379 >>> Sending CLUSTER FORGET messages to the cluster... >>> SHUTDOWN the node.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意,先下線從節點,在下線主節點,以免不必要的全量復制操作。對6379節點做忘記下線節點的操作,那么經過一段時間,集群中的其他節點也都會忘記。

127.0.0.1:6380> CLUSTER NODES 6fb7dfdb6188a9fe53c48ea32d541724f36434e9 127.0.0.1:6383 slave 8f285670923d4f1c599ecc93367c95a30fb8bf34 0 1496744890808 11 connecte 29978c0169ecc0a9054de7f4142155c1ab70258b 127.0.0.1:6379 master - 0 1496744892814 7 connected 0-5461 66478bda726ae6ba4e8fb55034d8e5e5804223ff 127.0.0.1:6381 master - 0 1496744891810 2 connected 10923-16383 e0c7961a1b07ab655bc31d8dfd583da565ec167d 127.0.0.1:6384 slave 66478bda726ae6ba4e8fb55034d8e5e5804223ff 0 1496744888804 2 connected 8f285670923d4f1c599ecc93367c95a30fb8bf34 127.0.0.1:6380 myself,master - 0 0 11 connected 5462-10922 961097d6be64ebd2fd739ff719e97565a8cee7b5 127.0.0.1:6382 slave 29978c0169ecc0a9054de7f4142155c1ab70258b 0 1496744889805 7 connected
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

6380端口的主節點已經忘記了下線節點,因此下線節點已經安全的下線。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM