版權聲明:本文爲博主原創文章,未經博主容許不得轉載。node
Redis
提供了靈活的節點擴容和收縮方案。在不影響集羣對外服務的狀況下,能夠爲集羣添加節點進行擴容也能夠對下線節點進行縮容。算法
咱們在Redis Cluster 介紹與搭建這篇文章中搭建了一個三主三從的Redis
集羣(以下圖所示)。在搭建 Redis Cluster 通訊流程剖析這篇博客中根據源碼詳細剖析了搭建集羣的流程。數據庫
本篇博客要講的是,Redis
集羣的擴容和縮容過程。安全
咱們先根據Redis Cluster 介紹與搭建將如圖的集羣搭建起來,查看搭建的效果。markdown
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
對應的主節點負責的槽位信息,以下圖所示:分佈式
擴容集羣是分佈式存儲最多見的需求,Redis
集羣擴容能夠分爲以下步驟:工具
咱們須要兩個節點,端口分別爲6385
和6386
,配置和以前集羣節點配置基本相同,除了端口不一樣,以便於管理。6385
節點配置以下:post
port 6385 //端口 cluster-enabled yes //開啓集羣模式 cluster-config-file nodes-6385.conf //集羣內部的配置文件 cluster-node-timeout 15000 //節點超時時間,單位毫秒 // 其餘配置和單機模式相同
啓動兩個節點學習
sudo redis-server conf/redis-6385.conf sudo redis-server conf/redis-6386.conf
啓動後的新節點會做爲孤兒節點運行,沒有和其餘節點與之通訊。
咱們能夠經過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 ......
也可使用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 ......
這兩種方法能夠,新加入的節點都是主節點,由於沒有負責槽位,因此不能接受任何讀寫操做,對於新加入的節點,咱們能夠有兩個操做:
當咱們將新節點加入集羣后,咱們就能夠將槽和數據遷移到新的節點,遷移的方法也有兩種,可使用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
原本在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; }
咱們已經獲取了要遷移的槽,是6918
。所以,流程以下:
6385
節點中,將槽6918
設置爲導入狀態127.0.0.1:6385> CLUSTER SETSLOT 6918 importing 8f285670923d4f1c599ecc93367c95a30fb8bf34 OK // 8f285670923d4f1c599ecc93367c95a30fb8bf34 是 6380 節點的名字
目標6385
節點中,查看槽6918
導入狀態
127.0.0.1:6385> CLUSTER NODES cb987394a3acc7a5e606c72e61174b48e437cedb 127.0.0.1:6385 myself,master - 0 0 8 connected [6918-<-8f285670923d4f1c599ecc93367c95a30fb8bf34]
6380
節點中,將槽6918
設置爲導出狀態127.0.0.1:6380> CLUSTER SETSLOT 6918 migrating cb987394a3acc7a5e606c72e61174b48e437cedb OK // cb987394a3acc7a5e606c72e61174b48e437cedb 是 6385 節點的名字
源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]
6918
中的鍵127.0.0.1:6380> CLUSTER GETKEYSINSLOT 6918 5 1) "key:{test}:555" 2) "key:{test}:666" 3) "key:{test}:777"
確認一下這三個鍵是否存在於源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"
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
批量遷移版本的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(若是存在)
當遷移完成後,咱們在源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
最後,咱們只需向任意節點發送CLUSTER SETSLOT <slot> NODE <target_name>
命令,將槽指派的信息發送給節點,而後這個節點會將這個指派信息發送至整個集羣。
CLUSTER SETSLOT 6918 node cb987394a3acc7a5e606c72e61174b48e437cedb // cb987394a3acc7a5e606c72e61174b48e437cedb 是 6385 節點的名字
在6381
節點執行命令
127.0.0.1:6381> CLUSTER SETSLOT 6918 node cb987394a3acc7a5e606c72e61174b48e437cedb OK
在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 // 過濾掉從節點和未指派槽的主節點
能夠看到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
到此就完成了集羣的擴容。集羣關係以下圖所示:
收縮集羣覺得着縮減規模,須要從集羣中安全下線部分節點。須要考慮兩種狀況:
咱們此次使用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: ...
查看一下結果:
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
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.
注意,先下線從節點,在下線主節點,以避免沒必要要的全量複製操做。對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
6380
端口的主節點已經忘記了下線節點,所以下線節點已經安全的下線。