Redis總結(八)如何搭建高可用的Redis叢集
以前總結Redis 的一些基本的安裝和使用,大家可以這這裡檢視Redis 系列文章:https://www.cnblogs.com/zhangweizhong/category/771056.html。
今天補一下redis叢集功能吧。需要注意,Redis 3.0 以後才有叢集的功能,下載Redis的時候注意下版本。
1. Redis叢集原理
先看看redis-cluster架構圖:
架構細節:
(1)所有的redis節點彼此互聯(PING-PONG機制),內部使用二進位制協議優化傳輸速度和頻寬。
(2)節點的fail是通過叢集中超過半數的節點檢測失效時才生效。
(3)客戶端與redis節點直連,不需要中間proxy層,客戶端不需要連線叢集所有節點,連線叢集中任何一個可用節點即可。
(4)redis-cluster把所有的物理節點對映到[0-16383]slot(雜湊槽)上,cluster 負責維護node<->slot<->value。
Redis 叢集中內建了 16384 個slot(雜湊槽),當需要在 Redis 叢集中放置一個 key-value 時,redis 先對 key 使用 crc16 演算法算出一個結果,然後把結果對 16384 求餘數,這樣每個 key 都會對應一個編號在 0-16383 之間的雜湊槽,redis 會根據節點數量大致均等的將雜湊槽對映到不同的節點。
容錯機制: redis-cluster投票
(1)領著投票過程是叢集中所有master參與,如果半數以上master節點與master節點通訊超過(cluster-node-timeout),認為當前master節點掛掉.
(2):什麼時候整個叢集不可用(cluster_state:fail)?
a:如果叢集任意master掛掉,且當前master沒有slave.叢集進入fail狀態,也可以理解成叢集的slot對映[0-16383]不完成時進入fail狀態.
b:如果叢集超過半數以上master掛掉,無論是否有slave叢集進入fail狀態.
注意:1. 當叢集不可用時,所有對叢集的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)錯誤。
2. redis-3.0.0.rc1加入cluster-require-full-coverage引數,預設關閉,開啟改配置,允許叢集相容部分失敗。
2. 安裝Redis
redis 的單機安裝之前已經講過,網路上也有很多教程,這裡就不重複了。
文章最後提供了Redis 3.0 的原始碼,Redis叢集指令碼等資源。大家可以用我提供的版本來測試。
3. 安裝ruby環境
redis3.0 原始碼中自帶的叢集管理工具redis-trib.rb依賴ruby環境,首先需要安裝ruby環境:
1. 安裝ruby環境
yum install ruby yum install rubygems
2. 安裝ruby和redis的介面程式
拷貝redis-3.0.0.gem至/usr/local下
執行:gem install /usr/local/redis-3.0.0.gem
4. 建立叢集
叢集結點規劃
一般Redis叢集的例項,都安裝在各個主從伺服器上,這裡為了演示方便,只是在同一臺伺服器用不同的埠表示不同的redis伺服器,如下:
主節點:172.16.0.17:7001,172.16.0.17.3:7002,172.16.0.17:7003
從節點:172.16.0.17:7004,172.16.0.17:7005,172.16.0.17:7006
1. 在/usr/local下建立redis-cluster目錄,其下建立Redis01到Redis06等6個redis例項,埠號為:7001-7006,具體目錄如下:
2. 將redis原始碼目錄src下的redis-trib.rb拷貝到redis-cluster目錄下。
3. 修改每個redis例項的redis.conf配置檔案:
port 7001 //這裡要改成各個例項對應的埠,7001-7006 #bind 172.16.0.17 cluster-enabled yes
啟動每個結點redis服務
分別進入Redis01、Redis02、...Redis06目錄,執行:
./redis-server ./redis.conf
檢視redis程序:ps aux|grep redis
以上,Redis 的6個例項,就已經啟動了。
執行建立叢集命令
執行redis-trib.rb,此指令碼是ruby指令碼,它依賴ruby環境。
./redis-trib.rb create --replicas 1 172.16.0.17:7001 172.16.0.17:7002 172.16.0.17:7003 172.16.0.17:7004 172.16.0.17:7005 172.16.0.17:7006
說明:
redis叢集至少需要3個主節點,每個主節點有一個從節點總共6個節點
replicas指定為1表示每個主節點有一個從節點
注意:
如果執行時報如下錯誤:
[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0
解決方法是刪除生成的配置檔案nodes.conf,如果不行則說明現在建立的結點包括了舊叢集的結點資訊,需要刪除redis的持久化檔案後再重啟redis,比如:appendonly.aof、dump.rdb
建立叢集輸出如下:
>>> Creating cluster Connecting to node 172.16.0.17:7001: OK Connecting to node 172.16.0.17:7002: OK Connecting to node 172.16.0.17:7003: OK Connecting to node 172.16.0.17:7004: OK Connecting to node 172.16.0.17:7005: OK Connecting to node 172.16.0.17:7006: OK >>> Performing hash slots allocation on 6 nodes... Using 3 masters: 172.16.0.17:7001 172.16.0.17:7002 172.16.0.17:7003 Adding replica 172.16.0.17:7004 to 172.16.0.17:7001 Adding replica 172.16.0.17:7005 to 172.16.0.17:7002 Adding replica 172.16.0.17:7006 to 172.16.0.17:7003 M: cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 172.16.0.17:7001 slots:0-5460 (5461 slots) master M: 4e7c2b02f0c4f4cfe306d6ad13e0cfee90bf5841 172.16.0.17:7002 slots:5461-10922 (5462 slots) master M: 1a8420896c3ff60b70c716e8480de8e50749ee65 172.16.0.17:7003 slots:10923-16383 (5461 slots) master S: 69d94b4963fd94f315fba2b9f12fae1278184fe8 172.16.0.17:7004 replicates cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 S: d2421a820cc23e17a01b597866fd0f750b698ac5 172.16.0.17:7005 replicates 4e7c2b02f0c4f4cfe306d6ad13e0cfee90bf5841 S: 444e7bedbdfa40714ee55cd3086b8f0d5511fe54 172.16.0.17:7006 replicates 1a8420896c3ff60b70c716e8480de8e50749ee65 Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join... >>> Performing Cluster Check (using node 172.16.0.17:7001) M: cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 172.16.0.17:7001 slots:0-5460 (5461 slots) master M: 4e7c2b02f0c4f4cfe306d6ad13e0cfee90bf5841 172.16.0.17:7002 slots:5461-10922 (5462 slots) master M: 1a8420896c3ff60b70c716e8480de8e50749ee65 172.16.0.17:7003 slots:10923-16383 (5461 slots) master M: 69d94b4963fd94f315fba2b9f12fae1278184fe8 172.16.0.17:7004 slots: (0 slots) master replicates cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 M: d2421a820cc23e17a01b597866fd0f750b698ac5 172.16.0.17:7005 slots: (0 slots) master replicates 4e7c2b02f0c4f4cfe306d6ad13e0cfee90bf5841 M: 444e7bedbdfa40714ee55cd3086b8f0d5511fe54 172.16.0.17:7006 slots: (0 slots) master replicates 1a8420896c3ff60b70c716e8480de8e50749ee65 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
5. 查詢叢集資訊
叢集建立成功登陸任意redis結點查詢叢集中的節點情況。
客戶端以叢集方式登陸:
./redis-cli -c -h 172.16.0.17 -p 7001 -c //其中-c表示以叢集方式連線redis,-h指定ip地址,-p指定埠號
查詢叢集資訊
cluster nodes 查詢叢集結點資訊
cluster info 查詢叢集狀態資訊
6. 新增主節點
叢集建立成功後可以向叢集中新增節點,下面是新增一個master主節點
1. 增加Redis07例項,參考叢集結點規劃章節新增一個“7007”目錄作為新節點。
2. 將Redis07例項新增到叢集中,執行下邊命令:
./redis-trib.rb add-node 172.16.0.17:7007 172.16.0.17:7001
3. 檢視叢集結點發現7007已新增到叢集中:
[root@VM_0_17_centos redis-cluster]# ./redis-trib.rb add-node 172.16.0.17:7007 172.16.0.17:7001 >>> Adding node 172.16.0.17:7007 to cluster 172.16.0.17:7001 Connecting to node 172.16.0.17:7001: OK .
.
.
Connecting to node 172.16.0.17:7003: OK Connecting to node 172.16.0.17:7005: OK Connecting to node 172.16.0.17:7002: OK Connecting to node 172.16.0.17:7006: OK Connecting to node 172.16.0.17:7004: OK >>> Performing Cluster Check (using node 172.16.0.17:7001) M: 977962f18ec51f363747961137dc903f0078b248 172.16.0.17:7001 slots:0-5460 (5461 slots) master 1 additional replica(s) M: defe4ce0421ee6b50bdab3da58754e98cc80fca3 172.16.0.17:7003 slots:10923-16383 (5461 slots) master 1 additional replica(s) S: a64fc273c0b90700397f5bac2b393dc5587d8ba8 172.16.0.17:7005 slots: (0 slots) slave replicates f277758189eba36c5b5732e9189d8554bf4385cb M: f277758189eba36c5b5732e9189d8554bf4385cb 172.16.0.17:7002 slots:5461-10922 (5462 slots) master 1 additional replica(s) S: 4f16e5adcc141ca284d4a9ec6d04f455aee84a48 172.16.0.17:7006 slots: (0 slots) slave replicates defe4ce0421ee6b50bdab3da58754e98cc80fca3 S: 479d5a077893184cd0b05a8e1b6cb5c0625215f4 172.16.0.17:7004 slots: (0 slots) slave replicates 977962f18ec51f363747961137dc903f0078b248 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. Connecting to node 172.16.0.17:7007: OK
.
.
. >>> Send CLUSTER MEET to node 172.16.0.17:7007 to make it join the cluster. [OK] New node added correctly.
雜湊槽重新分配
新增完主節點後,叢集並不會自動給新新增的節點分配雜湊槽,需要我們手動對主節點進行hash槽分配重新分配,這樣該主節才可以儲存資料。
redis叢集有16384個槽,叢集中的每個結點分配自已槽,通過檢視叢集結點可以看到槽佔用情況。可以看到剛才新增的主節點Redis07,沒有分配雜湊槽(slot)。
下面就來說說如何給剛新增的Redis01結點分配槽:
第一步:連線上叢集
./redis-trib.rb reshard 172.16.0.17:7001 //(連線叢集中任意一個可用結點都行)
第二步:輸入要分配的槽數量
第三步:輸入接收槽的結點id
這裡準備給Redis07分配雜湊槽,通過cluster nodes檢視Redis07節點id為:e8461f9743e186ae8f67ed301d2d971186b1cc93
輸入:e8461f9743e186ae8f67ed301d2d971186b1cc93,
第四步:輸入源結點id
如果只是想從單個主節點獲取雜湊槽,那直接輸入相應的節點id即可。
如果想從所有的主節點獲取輸入:all,
第五步:輸入yes開始移動槽到目標結點id
第六步:分配完成之後,可以查詢叢集節點資訊,檢視雜湊槽是否分配成功。
7. 新增從節點
叢集建立成功後可以向叢集中新增節點,下面是新增一個slave從節點的命令。
./redis-trib.rb add-node --slave --master-id 主節點id 新增節點的ip和埠 叢集中已存在節點ip和埠
1. 新增Redis08例項為從結點,將Redis08作為Redis07的從結點。
執行如下命令:
./redis-trib.rb add-node --slave --master-id e8461f9743e186ae8f67ed301d2d971186b1cc93 172.16.0.17:7008 172.16.0.17:7001
e8461f9743e186ae8f67ed301d2d971186b1cc93 是Redis07例項的節點id,可通過cluster nodes檢視。
注意:如果原來該結點在叢集中的配置資訊已經生成叢集節點的配置檔案(如果叢集配置cluster-config-file預設指定則為nodes.conf),這時可能會報錯:
[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0
解決方法是:刪除生成的配置檔案nodes.conf,刪除後再執行./redis-trib.rb add-node指令
2. 檢視叢集中的結點,剛新增的Redis08已經成為Redis07的從節點:
8. 刪除結點:
叢集建立成功後可以向叢集中刪除其中的一個節點,應該怎麼刪除呢?
執行如下命令即可:
./redis-trib.rb del-node 172.16.0.17 :7005 e8461f9743e186ae8f67ed301d2d971186b1cc93
注意:刪除已經分配了有hash槽的節點會失敗,報錯如下:
[ERR] Node 172.16.0.17:7007 is not empty! Reshard data away and try again.
解決辦法就是:將該結點佔用的hash槽分配出去,請參考前面雜湊槽重新分配的操作,這裡就不重複了。
最後
以上就已經將如何搭建redis的叢集講完了。
redis3.0原始碼和ruby指令碼,點選這裡下載。
&n