Redis Cluster是Redis官方的一個高可用分佈式解決方案。Redis Cluster中共有2 ^ 14(16384)個槽,建立集羣后,須要將這些槽均分給各個節點。node
Redis集羣通常由多個節點組成,節點數量至少爲 6 個,才能保證組成完整高可用的集羣。Redis集羣節點規劃以下:redis
節點名稱 | 端口號 | 主/從節點 | 複製的節點 |
---|---|---|---|
redis-6379 | 6379 | 主節點 | --- |
redis-6378 | 6378 | 主節點 | --- |
redis-6377 | 6377 | 主節點 | --- |
redis-6376 | 6376 | 從節點 | redis-6379 |
redis-6375 | 6375 | 從節點 | redis-6378 |
redis-6374 | 6374 | 從節點 | redis-6377 |
建議爲集羣內全部節點統一目錄,通常劃分三個目錄:conf、data、log,分別存放 配置、數據 和 日誌 相關文件。ruby
$ tree -L 2
.
├── conf
│ ├── redis-6374.conf
│ ├── redis-6375.conf
│ ├── redis-6376.conf
│ ├── redis-6377.conf
│ ├── redis-6378.conf
│ └── redis-6379.conf
├── data
│ ├── redis-6374
│ ├── redis-6375
│ ├── redis-6376
│ ├── redis-6377
│ ├── redis-6378
│ └── redis-6379
└── log
├── redis-6374.log
├── redis-6375.log
├── redis-6376.log
├── redis-6377.log
├── redis-6378.log
└── redis-6379.log
9 directories, 12 files
複製代碼
這裏只需將redis.conf複製6份到conf目錄下,更改成cluster所需的配置。data下新建6個文件夾,分別對應6個節點(用節點名命名)。log下新建6個日誌文件(也是用節點名命名)。bash
修改配置文件以下,這是redis-6379的配置,其它五個配置相似。分佈式
# redis後臺運行
daemonize yes
# 數據存放目錄
dir /usr/local/redis-cluster/data/redis-6379
# 日誌文件
logfile /usr/local/redis-cluster/log/redis-6379.log
# 端口號
port 6379
# 開啓集羣模式
cluster-enabled yes
# 集羣的配置,配置文件首次啓動自動生成
# 這裏只需指定文件名便可,集羣啓動成功後會自動在data目錄下建立
cluster-config-file "nodes-6379.conf"
# 請求超時,設置10秒
cluster-node-timeout 10000
複製代碼
分別啓動6個節點:工具
sudo redis-server conf/redis-6379.conf
sudo redis-server conf/redis-6378.conf
sudo redis-server conf/redis-6377.conf
sudo redis-server conf/redis-6376.conf
sudo redis-server conf/redis-6375.conf
sudo redis-server conf/redis-6374.conf
複製代碼
查看redis-6379的日誌:測試
11003:C 02 Feb 2020 22:45:04.655 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
11003:C 02 Feb 2020 22:45:04.656 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=11003, just started
11003:C 02 Feb 2020 22:45:04.657 # Configuration loaded
11004:M 02 Feb 2020 22:45:04.674 * Increased maximum number of open files to 10032 (it was originally set to 1024).
11004:M 02 Feb 2020 22:45:04.679 * No cluster configuration found, I'm 7d480c106752e0ba4be3efaf6628bd7c8c124013 11004:M 02 Feb 2020 22:45:04.788 * Running mode=cluster, port=6379. 11004:M 02 Feb 2020 22:45:04.789 # Server initialized 11004:M 02 Feb 2020 22:45:04.790 * Ready to accept connections 複製代碼
能夠看到Redis在集羣模式下啓動,由於初始的時候沒有集羣配置,因此自動建立了配置(文件名就是在redis-6379.conf中指定的)。ui
而後來看一下自動建立的及集羣配置。這個文件記錄了集羣的初始狀態,前面那個很長的字符串就是節點ID。spa
7d480c106752e0ba4be3efaf6628bd7c8c124013 127.0.0.1:6379@16379 myself,master - 0 1580657311000 0 connected
vars currentEpoch 5 lastVoteEpoch 0
複製代碼
Redis Cluster集羣模式下的節點彼此經過Gossip協議進行通訊,但集羣中的節點須要先進行握手通訊。命令行
節點握手須要由客戶端發起命令:cluster meet {ip} {port},一個客戶端能夠完成整個集羣的握手(握手其實是將對方節點加入集羣中,握手成功後該狀態會經過下消息在集羣中傳播,其它節點就會自動發現新節點而後發起握手,最後全部節點都彼此感知並組成集羣)。
進入redis-6379客戶端發起握手:
127.0.0.1:6379> cluster meet 127.0.0.1 6378
127.0.0.1:6379> cluster meet 127.0.0.1 6377
127.0.0.1:6379> cluster meet 127.0.0.1 6376
127.0.0.1:6379> cluster meet 127.0.0.1 6375
127.0.0.1:6379> cluster meet 127.0.0.1 6374
複製代碼
查看集羣的節點:
127.0.0.1:6379> cluster nodes
13793dee9c570fd88297fd406ecb9c6a83ab670d 127.0.0.1:6374@16374 master - 0 1580655577754 5 connected
7d480c106752e0ba4be3efaf6628bd7c8c124013 127.0.0.1:6379@16379 myself,master - 0 1580655577000 0 connected
359acf2a5134bdc0059464100ad712564062b731 127.0.0.1:6375@16375 master - 0 1580655576000 4 connected
2f2b41c194343fe88845fea5caa3796c50f71bbb 127.0.0.1:6378@16378 master - 0 1580655575000 1 connected
169fae6f05e58bd944057d5f814abefdd34eb4b2 127.0.0.1:6377@16377 master - 0 1580655576000 2 connected
3fe3f423e8ba0c289a71702a78ad44a585c4a0fe 127.0.0.1:6376@16376 master - 0 1580655576745 3 connected
複製代碼
可是此時集羣還不能使用,由於尚未給節點分配槽,因此不能對數據進行讀寫操做。
能夠查看集羣的信息(集羣的狀態處於fail狀態,且分配的槽爲0):
127.0.0.1:6379> cluster info
cluster_state:fail
cluster_slots_assigned:0
...
複製代碼
Redis集羣將全部的數據映射到16384個槽中,每一個key都會對應一個槽,只有把槽分配給了節點,節點才能響應與槽相關的命令。
這裏爲了方便,直接用命令行進行槽的分配。
redis-cli -p 6379 cluster addslots {0..5461}
redis-cli -p 6378 cluster addslots {5462..10922}
redis-cli -p 6377 cluster addslots {10922..16383}
複製代碼
將16384個槽平均的分給3個節點,而後查看集羣的狀態,能夠發現變成了OK。
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
...
複製代碼
再查看集羣的槽,能夠看到每一個節點分配到的槽的範圍和節點的信息。
127.0.0.1:6379> cluster slots
1) 1) (integer) 0
2) (integer) 5461
3) 1) "127.0.0.1"
2) (integer) 6379
3) "7d480c106752e0ba4be3efaf6628bd7c8c124013"
2) 1) (integer) 5462
2) (integer) 10922
3) 1) "127.0.0.1"
2) (integer) 6378
3) "2f2b41c194343fe88845fea5caa3796c50f71bbb"
3) 1) (integer) 10923
2) (integer) 16383
3) 1) "127.0.0.1"
2) (integer) 6377
3) "169fae6f05e58bd944057d5f814abefdd34eb4b2"
複製代碼
咱們一共啓動了6個節點,但這裏分配槽只用了3個節點,其它3個節點就是用於主從複製的,保證主節點出現故障時能夠進行故障轉移,從節點負責複製主節點槽信息和相關數據。能夠用如下命令讓一個節點變成從節點(該命令必定要在從節點客戶端上執行)。
redis-cli -p 6376
127.0.0.1:6376> cluster replicate 7d480c106752e0ba4be3efaf6628bd7c8c124013(這個是6379節點的ID)
OK
127.0.0.1:6376> exit
redis-cli -p 6375
127.0.0.1:6375> cluster replicate 2f2b41c194343fe88845fea5caa3796c50f71bbb(這個是6378節點的ID)
OK
127.0.0.1:6375> exit
redis-cli -p 6374
127.0.0.1:6374> cluster replicate 169fae6f05e58bd944057d5f814abefdd34eb4b2(這個是6377節點的ID)
OK
127.0.0.1:6374> exit
複製代碼
到此爲止,Redis Cluster集羣就搭建成功了,最後來看一下集羣節點的狀態(三主三從)
127.0.0.1:6379> cluster nodes
13793dee9c570fd88297fd406ecb9c6a83ab670d 127.0.0.1:6374@16374 slave 169fae6f05e58bd944057d5f814abefdd34eb4b2 0 1580657364167 5 connected
7d480c106752e0ba4be3efaf6628bd7c8c124013 127.0.0.1:6379@16379 myself,master - 0 1580657362000 0 connected 0-5461
359acf2a5134bdc0059464100ad712564062b731 127.0.0.1:6375@16375 slave 2f2b41c194343fe88845fea5caa3796c50f71bbb 0 1580657360000 4 connected
2f2b41c194343fe88845fea5caa3796c50f71bbb 127.0.0.1:6378@16378 master - 0 1580657363000 1 connected 5462-10922
169fae6f05e58bd944057d5f814abefdd34eb4b2 127.0.0.1:6377@16377 master - 0 1580657365175 2 connected 10923-16383
3fe3f423e8ba0c289a71702a78ad44a585c4a0fe 127.0.0.1:6376@16376 slave 7d480c106752e0ba4be3efaf6628bd7c8c124013 0 1580657363160 3 connected
複製代碼
能夠看到上面的集羣搭建很是的麻煩(先進行節點通訊,而後分配槽,最後還要指定從節點去複製主節點)。好在Redis爲咱們提供了工具可讓咱們輕鬆的搭建集羣。
我使用的是Redis5,若是是更低版本有一個工具redis-trib.rb,使用它時須要先安裝redis gem依賴(gem install redis
若是沒有ruby環境請先安裝ruby)。
先把上面手動搭建的集羣節點所有中止,並刪除數據目錄下的全部文件。
若是在以前的集羣中的某個節點存儲過數據或者集羣配置沒有刪除,會報相似錯誤[ERR] Node 127.0.0.1:6378 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
若是集羣配置未刪除,則刪除全部集羣配置,不然進入以前存儲數據的客戶端執行flushall
和cluster reset
清空數據並重置集羣。
而後從新啓動全部節點。只需鍵入如下內容便可爲Redis 5建立集羣:
redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6378 127.0.0.1:6377 127.0.0.1:6376 127.0.0.1:6375 127.0.0.1:6374 --cluster-replicas 1
複製代碼
create 後面跟着的是6個節點的地址和端口,選項--cluster-replicas 1意味着爲每一個主節點都提供一個從節點。建立結果以下:
>>> Performing Cluster Check (using node 127.0.0.1:6379)
M: 872e3876ea53a1ba1a77af3fb5a8c72704ac0eab 127.0.0.1:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: e80c00d029005bb132b08ddbdb4029a10feff839 127.0.0.1:6376
slots: (0 slots) slave
replicates a6651e15af616cfe720c7731f8748fffbde56822
M: a6651e15af616cfe720c7731f8748fffbde56822 127.0.0.1:6378
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 10e8962e8ce4b0200c3ee5ffcf03d196f72f72fc 127.0.0.1:6374
slots: (0 slots) slave
replicates 872e3876ea53a1ba1a77af3fb5a8c72704ac0eab
M: 74af8a6c3dce0420707e5253fdb0a2f0c039b1a3 127.0.0.1:6377
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: f96b0261c775cf10a254f28374a4ed73c2977b1b 127.0.0.1:6375
slots: (0 slots) slave
replicates 74af8a6c3dce0420707e5253fdb0a2f0c039b1a3
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
複製代碼
redis-cli加個-c以switch模式啓動,將支持集羣的使用。
$ redis-cli -c -p 6379
127.0.0.1:6379> set name cluster
-> Redirected to slot [5798] located at 127.0.0.1:6378
OK
127.0.0.1:6378> get name
"cluster"
複製代碼
當在redis-6379使用鍵命令來設置name的值時,對應的槽爲5798,這個槽是屬於redis-6378節點負責的,因此switch模式會自動重定向到redis-6378節點來完成鍵命令。
從新分片其實也就是槽的遷移。將哈希槽從一個或幾個節點遷移到另外一個節點。
Redis官方也是提供了命令用來從新分片的,若是Redis的版本低於5的話仍是使用redis-trib.rb這個工具。
redis-cli --cluster reshard 127.0.0.1:6379
複製代碼
在這裏只須要指定一個節點,redis-cli將自動找到其餘節點。
首先會測試集羣的運行狀態,而後詢問你要從新分配多少個槽(我這裏指定了1000個槽)。 How many slots do you want to move (from 1 to 16384)?
而後咱們須要指定從新分片的目標ID(也就是指定哪一個節點來接收這些從新分配的槽)。
能夠經過如下命令來查看某個節點的信息(裏面包括了節點的ID)。
redis-cli -p 6379 cluster nodes | grep myself
872e3876ea53a1ba1a77af3fb5a8c72704ac0eab 127.0.0.1:6379@16379 myself,master - 0 1580801413000 7 connected 0-5961 10923-11421
複製代碼
最終須要指定從哪些節點獲取槽(這裏簡單的指定all也就是全部的節點)。就會開始執行從新分片了,經過終端能夠看到槽正在從一個節點移動到另外一個節點。
最後檢查集羣狀態能夠發現目標節點的槽數量變成了6461。
redis-cli --cluster check 127.0.0.1:6379
127.0.0.1:6379 (872e3876...) -> 1 keys | 6461 slots | 1 slaves.
127.0.0.1:6378 (a6651e15...) -> 0 keys | 4961 slots | 1 slaves.
127.0.0.1:6377 (74af8a6c...) -> 0 keys | 4962 slots | 1 slaves.
複製代碼
先來看一下當前集羣中的節點:
redis-cli -a redis666 cluster nodes
872e3876ea53a1ba1a77af3fb5a8c72704ac0eab 127.0.0.1:6379@16379 myself,master - 0 1580823411000 7 connected 0-5961 10923-11421
74af8a6c3dce0420707e5253fdb0a2f0c039b1a3 127.0.0.1:6377@16377 slave f96b0261c775cf10a254f28374a4ed73c2977b1b 0 1580823412846 9 connected
e80c00d029005bb132b08ddbdb4029a10feff839 127.0.0.1:6376@16376 slave a6651e15af616cfe720c7731f8748fffbde56822 0 1580823411000 4 connected
f96b0261c775cf10a254f28374a4ed73c2977b1b 127.0.0.1:6375@16375 master - 0 1580823409820 9 connected 11422-16383
a6651e15af616cfe720c7731f8748fffbde56822 127.0.0.1:6378@16378 master - 0 1580823412000 2 connected 5962-10922
10e8962e8ce4b0200c3ee5ffcf03d196f72f72fc 127.0.0.1:6374@16374 slave 872e3876ea53a1ba1a77af3fb5a8c72704ac0eab 0 1580823410835 7 connected
複製代碼
這裏用命令debug segfault讓master節點6378崩潰(根據上面的信息能夠看到redis-6378的從節點是redis-6376)。
redis-cli -p 6378 debug segfault
複製代碼
而後等待一段時間,會發現已經自動完成了故障轉移,redis-6376成了新的master節點(redis-6378處於fail狀態):
e80c00d029005bb132b08ddbdb4029a10feff839 127.0.0.1:6376@16376 master - 0 1580823678628 10 connected 5962-10922
a6651e15af616cfe720c7731f8748fffbde56822 127.0.0.1:6378@16378 master,fail - 1580823551245 1580823549000 2 disconnected
複製代碼
再次啓動redis-6378,cluster會從新將它加入集羣,並讓它成爲從節點最少的那個master節點的從節點(在這裏就是redis-6376)。
e80c00d029005bb132b08ddbdb4029a10feff839 127.0.0.1:6376@16376 master - 0 1580823829221 10 connected 5962-10922
a6651e15af616cfe720c7731f8748fffbde56822 127.0.0.1:6378@16378 slave e80c00d029005bb132b08ddbdb4029a10feff839 0 1580823830226 10 connected
複製代碼
隨便進入一個從節點(只能是從節點)中,執行cluster failover
進行手動故障轉移(手動故障轉移只是將主節點和從節點的關係換了一下)。
這裏對redis-6374進行手動故障轉移,執行以前節點的狀態(redis-6374是從節點,redis-6379是主節點)。
10e8962e8ce4b0200c3ee5ffcf03d196f72f72fc 127.0.0.1:6374@16374 myself,slave 872e3876ea53a1ba1a77af3fb5a8c72704ac0eab 0 1580825791000 6 connected
872e3876ea53a1ba1a77af3fb5a8c72704ac0eab 127.0.0.1:6379@16379 master - 0 1580825792000 7 connected 789-5961 10923-11421
複製代碼
執行以後的狀態(redis-6374是主節點,redis-6379是從節點)
10e8962e8ce4b0200c3ee5ffcf03d196f72f72fc 127.0.0.1:6374@16374 myself,master - 0 1580825812000 12 connected 789-5961 10923-11421
872e3876ea53a1ba1a77af3fb5a8c72704ac0eab 127.0.0.1:6379@16379 slave 10e8962e8ce4b0200c3ee5ffcf03d196f72f72fc 0 1580825813000 12 connected
複製代碼
按照以前的配置,新增長一個節點redis-6373,而後啓動它。使用如下命令將它加入到集羣中。
# 127.0.0.1:6373指的是新加入集羣中的節點的ip和端口
# 127.0.0.1:6379指的是集羣中的某個節點的ip和地址(隨便哪一個節點都行)
redis-cli --cluster add-node 127.0.0.1:6373 127.0.0.1:6379
複製代碼
其實這個命令的做用和cluster meet是同樣的,就是用於節點握手通訊(惟一不同的就是執行前會檢查集羣的狀態)。
還記得以前手動搭建集羣的時候,節點握手完成後須要給節點分配槽。由於這裏的16384個槽都已經分完了,因此這裏使用從新分片來給新節點分配槽(新節點就是從新分片的目標節點)。
從新分片後來看一下新節點所負責的槽(全部的節點分了2000個槽給新節點,能夠發現新節點的槽有三個範圍) .
M: 533168c99a03b5593408818dabc1db36396a221f 127.0.0.1:6373
slots:[0-788],[5962-6566],[11422-12026] (1999 slots) master
複製代碼
要刪除一個從節點,只需使用del-node命令:
# 127.0.0.1:6379是集羣中的任意一個節點Ip和端口
# node-id就是要刪除的節點ID
redis-cli --cluster del-node 127.0.0.1:6379 <node-id>
複製代碼
也能夠用相同的方法刪除主節點,可是要刪除主節點,它必須爲空。若是主節點不爲空,則須要先將數據從其從新分片到全部其餘主節點。不然可使用手動故障轉移的方式將主節點降爲從節點,而後再執行刪除。