Redis Cluster 集群使用(3)


簡介

Redis3.0版本之前,可以通過Redis Sentinel(哨兵)來實現高可用(HA),從3.0版本之后,官方推出了Redis Cluster,它的主要用途是實現數據分片(Data Sharding),不過同樣可以實現HA,是官方當前推薦的方案。
在Redis Sentinel模式中,每個節點需要保存全量數據,冗余比較多,而在Redis Cluster模式中,每個分片只需要保存一部分的數據,對於內存數據庫來說,還是要盡量的減少冗余。在數據量太大的情況下,故障恢復需要較長時間。

 

Redis Cluster本身提供了自動將數據分散到Redis Cluster不同節點的能力,分區實現的關鍵點問題包括:

  1. 如何將數據自動的打散到不同的節點,使得不同節點的存儲數據相對均勻;
  2. 如何保證客戶端能夠訪問到正確的節點和數據;
  3. 如何保證重新分片的過程中不影響正常服務。

 

數據分區

 

(這部分的資料來自於:https://blog.csdn.net/qq2430/article/details/80716313 感謝作者的分享)

 

在介紹Redis Cluster之前,先簡單介紹下分布式數據庫的數據分區。所謂的數據分區就是將一個較大的數據集分布在不同的節點上進行儲存。

常見的數據分區方式:

  1. 節點取余;
  2. 一致性哈希;
  3. 虛擬槽

 

【節點取余】

根據key的hash值和節點數取模的方式計算出節點ID,然后向對應的節點提交數據,如下:

 

對於這種分區方式,新增或者刪除節點會造成大量的數據遷移。假設數據集為:1 2 3... 10,那么數據分布應如下所示:

如果新增一個節點,那么數據分布會變成什么樣子呢?

比較結果:只有 1、2、3還分布在原來的節點上,其余所有的數據都進行了遷移。在這種分區方式下,如果新增的節點時原來節點的倍數時,遷移的節點數量會少很多。

 

【一致性哈希】

對於任何的哈希函數,都有其取值范圍。我們可以用環形結構來標識范圍。通過哈希函數,每個節點都會被分配到環上的一個位置,每個鍵值也會被映射到環上的一個位置,然后順時針找到相鄰的節點。如下圖所示,例如key分布在range1內,那么數據存儲在node2上。

 

對於這種分區方式,新增或者刪除節點會造成數據分布不均勻。假設數據集 1 2 3 ... 12,數據范圍也是1-12,那么數據分布應如下所示:

 

如果我們在node1和node2之間新增一個節點,那么數據分布應該變成什么樣子呢?

可以看到,我們只是將數據3進行了遷移。但是造成了每個節點負責的數據范圍不等。會造成數據分布不均等的問題。

 

【虛擬槽】

在 redis cluster中使用槽來存儲一定范圍內的數據集。每個redis節點上有一定數量的槽。當客戶端提交數據時,要先根據CRC16(key)&16383來計算出數據要落到哪個虛擬槽內。

假設我們有3個節點,那么可以按如下分配槽:

與節點取余和一致性哈希分區不同,虛擬槽分區是服務端分區。客戶端可以將數據提交到任意一個redis cluster 節點上,如果存儲該數據的槽不在這個節點上,則返回給客戶端目標節點信息,告知客戶端向目標節點提交數據。

 

Redis Cluster 原理介紹

RedisCluster是由多個同時服務於一個數據集合的Redis實例組成的整體,對於用戶來說,用戶只關注這個數據集合,而整個數據集合的某個數據子集存儲在哪個節點對於用戶來說是透明的。

redis cluster采用無中心結構,節點間使用gossip協議進行通信。每個節點保存數據和所有節點對應槽的映射關系。其架構圖如下:

 

 

Redis Cluster 特點如下:

  1. 所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬。
  2. 節點的fail是通過集群中超過半數的節點檢測失效時才生效。
  3. 客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可。
  4. redis-cluster把所有的物理節點映射到[0-16383]slot上,cluster 負責維護node -> slot -> value
  5. 集群消息通信通過集群總線通信,集群總線端口大小為客戶端服務端口+10000,這個10000是固定值;
  6. 客戶端和集群節點之間通信和通常一樣,通過文本協議進行;
  7. 集群節點不會代理查詢

 

Redis Cluster的具體實現細節是采用了Hash槽的概念,集群會預先分配16384個槽,並將這些槽分配給具體的服務節點,通過對Key進行CRC16(key)%16384運算得到對應的槽是哪一個,從而將讀寫操作轉發到該槽所對應的服務節點。當有新的節點加入或者移除的時候,再來遷移這些槽以及其對應的數據。在這種設計之下,我們就可以很方便的進行動態擴容或縮容。

 

【Redis Cluster投票:容錯】

 

  1. 投票過程是集群中所有master參與,如果半數以上master節點與master節點通信超時(cluster-node-timeout),認為當前master節點掛掉,對應master節點掛掉,slave會代替工作
  2. 如果集群超過半數以上master掛掉,無論是否有slave,集群進入fail狀態.

 

Redis Cluster集群搭建

(因為資源有限,本次在同一台主機上實現Redis Cluster)

1. 安裝不同端口的 6 個 redis 節點

[root@192.168.118.15 /usr/local/src]#yum install gcc* -y
[root@192.168.118.15 /usr/local/src]#ls
redis-4.0.10.tar.gz
[root@192.168.118.15 /usr/local/src]#tar xf redis-4.0.10.tar.gz 
[root@192.168.118.15 /usr/local/src]#cd redis-4.0.10
[root@192.168.118.15 /usr/local/src/redis-4.0.10]#mkdir -pv /usr/local/redis/{conf,db,log}
mkdir: created directory ‘/usr/local/redis’
mkdir: created directory ‘/usr/local/redis/conf’
mkdir: created directory ‘/usr/local/redis/db’
mkdir: created directory ‘/usr/local/redis/log’
[root@192.168.118.15 /usr/local/src/redis-4.0.10]#make PREFIX=/usr/local/redis/ install 

編譯完成后,修改配置文件

[root@192.168.118.15 /usr/local/src/redis-4.0.10]#mkdir -pv  /usr/local/redis/conf/63{79..84}
mkdir: created directory ‘/usr/local/redis/conf/6379mkdir: created directory ‘/usr/local/redis/conf/6380mkdir: created directory ‘/usr/local/redis/conf/6381mkdir: created directory ‘/usr/local/redis/conf/6382mkdir: created directory ‘/usr/local/redis/conf/6383mkdir: created directory ‘/usr/local/redis/conf/6384’
[root@192.168.118.15 /usr/local/src/redis-4.0.10]#for i in 6379 6380 6381 6382 6383 6384; do cp -a redis.conf /usr/local/redis/conf/$i/$i.conf ; done
[root@192.168.118.15 /usr/local/src/redis-4.0.10]#yum install tree -y
[root@192.168.118.15 /usr/local/src/redis-4.0.10]#cd /usr/local/redis/
[root@192.168.118.15 /usr/local/redis]#tree 
.
├── bin
│   ├── redis-benchmark
│   ├── redis-check-aof
│   ├── redis-check-rdb
│   ├── redis-cli
│   ├── redis-sentinel -> redis-server
│   └── redis-server
├── conf
│   ├── 6379
│   │   └── 6379.conf
│   ├── 6380
│   │   └── 6380.conf
│   ├── 6381
│   │   └── 6381.conf
│   ├── 6382
│   │   └── 6382.conf
│   ├── 6383
│   │   └── 6383.conf
│   └── 6384
│       └── 6384.conf
├── db
└── log

10 directories, 12 files

 

編寫修改配置文件腳本

[root@192.168.118.15 /usr/local/redis/conf]#vim modify_conf.sh
#!/bin/bash
for i in 6379  6380  6381  6382  6383  6384; do
  sed -i "s/daemonize no/daemonize yes/g" $i/$i.conf
  sed -i "s/bind 127.0.0.1/bind 0.0.0.0/g" $i/$i.conf
  sed -i "s/port 6379/port $i/g" $i/$i.conf
  sed -i "s/dbfilename dump.rdb/dbfilename dump-$i.rdb/g" $i/$i.conf
  sed -i "s/redis_6379.pid/redis_$i.pid/g" $i/$i.conf
  sed -i "s/dir \.\//dir \/usr\/local\/redis\/db\//g" $i/$i.conf
  sed -i "s/logfile \"\"/logfile \"\/usr\/local\/redis\/log\/redis-$i.log\"/g" $i/$i.conf
  sed -i "s/# cluster-enabled yes/cluster-enabled yes/g" $i/$i.conf
  sed -i "s/# cluster-config-file nodes-6379.conf/cluster-config-file nodes-$i.conf/g" $i/$i.conf
  sed -i "s/# cluster-node-timeout 15000/cluster-node-timeout 15000/g" $i/$i.conf
done

[root@192.168.118.15 /usr/local/redis/conf]#sh modify_conf.sh
sed -i "s/daemonize no/daemonize yes/g" $i/$i.conf    # 修改為后台運行
sed -i "s/bind 127.0.0.1/bind 0.0.0.0/g" $i/$i.conf    # 修改監聽ip
sed -i "s/port 6379/port $i/g" $i/$i.conf    # 修改監聽端口
sed -i "s/dbfilename dump.rdb/dbfilename dump-$i.rdb/g" $i/$i.conf    # 修改RDB模式持久化文件名
sed -i "s/redis_6379.pid/redis_$i.pid/g" $i/$i.conf    # 修改pid文件名
sed -i "s/dir \.\//dir \/usr\/local\/redis\/db\//g" $i/$i.conf    # 修改文件保存目錄
sed -i "s/logfile \"\"/logfile \"\/usr\/local\/redis\/log\/redis-$i.log\"/g" $i/$i.conf    # 修改日志文件目錄及文件名
sed -i "s/# cluster-enabled yes/cluster-enabled yes/g" $i/$i.conf    # 開啟集群模式
sed -i "s/# cluster-config-file nodes-6379.conf/cluster-config-file nodes-$i.conf/g" $i/$i.conf    # 定義集群配置文件(該文件無需手動創建,啟動自動生成)
sed -i "s/# cluster-node-timeout 15000/cluster-node-timeout 15000/g" $i/$i.conf    # 開啟集群節點無法連接超時時間
修改的配置各項注解

 

啟動服務

[root@192.168.118.15 /usr/local/redis/conf]#echo "export PATH=$PATH:/usr/local/redis/bin" > /etc/profile.d/redis.sh
[root@192.168.118.15 /usr/local/redis/conf]#source /etc/profile.d/redis.sh
[root@192.168.118.15 /usr/local/redis/conf]#for i in 6379  6380  6381  6382  6383  6384; do redis-server $i/$i.conf ; done
[root@192.168.118.15 /usr/local/redis/conf]#netstat -ntplu | egrep redis
tcp        0      0 0.0.0.0:16379           0.0.0.0:*               LISTEN      5520/redis-server 0 
tcp        0      0 0.0.0.0:16380           0.0.0.0:*               LISTEN      5522/redis-server 0 
tcp        0      0 0.0.0.0:16381           0.0.0.0:*               LISTEN      5524/redis-server 0 
tcp        0      0 0.0.0.0:16382           0.0.0.0:*               LISTEN      5526/redis-server 0 
tcp        0      0 0.0.0.0:16383           0.0.0.0:*               LISTEN      5531/redis-server 0 
tcp        0      0 0.0.0.0:16384           0.0.0.0:*               LISTEN      5533/redis-server 0 
tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      5520/redis-server 0 
tcp        0      0 0.0.0.0:6380            0.0.0.0:*               LISTEN      5522/redis-server 0 
tcp        0      0 0.0.0.0:6381            0.0.0.0:*               LISTEN      5524/redis-server 0 
tcp        0      0 0.0.0.0:6382            0.0.0.0:*               LISTEN      5526/redis-server 0 
tcp        0      0 0.0.0.0:6383            0.0.0.0:*               LISTEN      5531/redis-server 0 
tcp        0      0 0.0.0.0:6384            0.0.0.0:*               LISTEN      5533/redis-server 0

 

redis端口 --> 集群總線端口

6379 --> 16379
6380 --> 16380
6381 --> 16381
6382 --> 16382
6383 --> 16383
6384 --> 16384

 

 

redis cluster 集群創建

由於創建集群需要用到redis-trib這個命令,它依賴Ruby和RubyGems,因此我們要先安裝一下

[root@192.168.118.15 /usr/local/redis/conf]#yum install ruby rubygems -y

這里要注意下:查看ruby對應的版本下載支持的 redis.gem,具體對應關系及下載可以查看 https://rubygems.org/downloads/

[root@192.168.118.15 /usr/local/redis/conf]#ruby --version
ruby 2.0.0p353 (2013-11-22) [x86_64-linux]

下載redis-3.3.3.gem
[root@192.168.118.15 ~]#yum install wget -y
[root@192.168.118.15 ~]#wget https://rubygems.org/downloads/redis-3.3.3.gem --no-check-certificate
[root@192.168.118.15 ~]#gem install redis-3.3.3.gem     # 安裝redis.gem
Successfully installed redis-3.3.3
Parsing documentation for redis-3.3.3
Installing ri documentation for redis-3.3.3
1 gem installed
[root@192.168.118.15 ~]#gem list

*** LOCAL GEMS ***

bigdecimal (1.2.0)
io-console (0.4.2)
json (1.7.7)
psych (2.0.0)
rdoc (4.0.0)
redis (3.3.3)    # 安裝成功

 

 

創建集群
注意:redis-trib.rb 命令在 源碼的 src里面

[root@192.168.118.15 ~]#cp -a /usr/local/src/redis-4.0.10/src/redis-trib.rb /usr/local/redis/bin/
[root@192.168.118.15 ~]#redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:6379
127.0.0.1:6380
127.0.0.1:6381
Adding replica 127.0.0.1:6383 to 127.0.0.1:6379
Adding replica 127.0.0.1:6384 to 127.0.0.1:6380
Adding replica 127.0.0.1:6382 to 127.0.0.1:6381
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: 7bb6e7b6b77db35a306ff932a8a70277763e3504 127.0.0.1:6379
   slots:0-5460 (5461 slots) master
M: a798db2f4e6a756606677bf82b0488c517402412 127.0.0.1:6380
   slots:5461-10922 (5462 slots) master
M: 292362ebc26df9920de8e8c19fdad0d9a5e05fb7 127.0.0.1:6381
   slots:10923-16383 (5461 slots) master
S: fd583297b826fc92bc872d5a3a6e8bfda30a5eda 127.0.0.1:6382
   replicates 7bb6e7b6b77db35a306ff932a8a70277763e3504
S: a6d4cb574131b82d95f58c92c9fe5389dcb16f59 127.0.0.1:6383
   replicates a798db2f4e6a756606677bf82b0488c517402412
S: d984d502c61d2b3d64b0100a0179642d92c9f95d 127.0.0.1:6384
   replicates 292362ebc26df9920de8e8c19fdad0d9a5e05fb7
Can I set the above configuration? (type 'yes' to accept): yes    # 這里需要手動輸入 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 127.0.0.1:6379)
M: 7bb6e7b6b77db35a306ff932a8a70277763e3504 127.0.0.1:6379
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: fd583297b826fc92bc872d5a3a6e8bfda30a5eda 127.0.0.1:6382
   slots: (0 slots) slave
   replicates 7bb6e7b6b77db35a306ff932a8a70277763e3504
S: a6d4cb574131b82d95f58c92c9fe5389dcb16f59 127.0.0.1:6383
   slots: (0 slots) slave
   replicates a798db2f4e6a756606677bf82b0488c517402412
S: d984d502c61d2b3d64b0100a0179642d92c9f95d 127.0.0.1:6384
   slots: (0 slots) slave
   replicates 292362ebc26df9920de8e8c19fdad0d9a5e05fb7
M: a798db2f4e6a756606677bf82b0488c517402412 127.0.0.1:6380
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
M: 292362ebc26df9920de8e8c19fdad0d9a5e05fb7 127.0.0.1:6381
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

到此,Redis Cluster 已經搭建成功。

連接其中一個節點查看集群狀態:

[root@192.168.118.15 ~]#redis-cli -h 127.0.0.1 -p 6379 
127.0.0.1:6379> cluster info 
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:86
cluster_stats_messages_pong_sent:85
cluster_stats_messages_sent:171
cluster_stats_messages_ping_received:80
cluster_stats_messages_pong_received:86
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:171

# 查看集群節點狀態
127.0.0.1:6379> cluster nodes 
fd583297b826fc92bc872d5a3a6e8bfda30a5eda 127.0.0.1:6382@16382 slave 7bb6e7b6b77db35a306ff932a8a70277763e3504 0 1544091668241 4 connected
a6d4cb574131b82d95f58c92c9fe5389dcb16f59 127.0.0.1:6383@16383 slave a798db2f4e6a756606677bf82b0488c517402412 0 1544091668000 5 connected
7bb6e7b6b77db35a306ff932a8a70277763e3504 127.0.0.1:6379@16379 myself,master - 0 1544091668000 1 connected 0-5460
d984d502c61d2b3d64b0100a0179642d92c9f95d 127.0.0.1:6384@16384 slave 292362ebc26df9920de8e8c19fdad0d9a5e05fb7 0 1544091669244 6 connected
a798db2f4e6a756606677bf82b0488c517402412 127.0.0.1:6380@16380 master - 0 1544091669000 2 connected 5461-10922
292362ebc26df9920de8e8c19fdad0d9a5e05fb7 127.0.0.1:6381@16381 master - 0 1544091670247 3 connected 10923-16383

 

 

控制台信息顯示:當前集群中存在3個主節點和3個從節點,虛擬槽的分配是0-5460、5461-10922、10923-16383 說明我們集群已經搭建完成。
至此,Redis Cluster集群就搭建完成了。

注意:

  1. 如果想重新創建集群,需要登錄到每個節點,執行flushdb,然后執行cluster reset,重啟節點;
  2. 如果要批量殺掉Redis進程,可以使用pkill redis-server命令;
  3. 如果redis開啟了密碼認證,則需要在redis.conf中增加屬性 : masterauth yourpassword
  4. Redis開啟密碼認證后,在集群操作時問題會比較多,因此建議不要開啟密碼認證,搭配使用防火牆保證Redis的安全。

 

 

Redis Cluster 數據存儲及異常

客戶端在連接 redis cluster 的時候,可以將數據提交到任意一個redis cluster節點上,如果存儲該數據的槽不在這個節點上,則返回給客戶端moved異常,客戶端通過moved異常,永久的將請求轉移到目標節點,如下圖所示。

通過moved異常,客戶端可以知道目標節點並重新提交數據,但是這種情形效率不算高,那怎么解決這個問題的呢?

redis客戶端JedisCluster怎么解決這個問題的。

  1. 初始化時從集群中選一個可運行節點,使用cluster slots初始化槽和節點映射。
  2. 將cluster slots的結果映射到本地,為每個節點創建JedisPool。
  3. 准備執行命令。

 

現在我們來實際看下這個異常:
首先來看下redis cluster的節點信息,執行命令redis-cli cluster nodes

[root@192.168.118.15 ~]#redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> cluster nodes
fd583297b826fc92bc872d5a3a6e8bfda30a5eda 127.0.0.1:6382@16382 slave 7bb6e7b6b77db35a306ff932a8a70277763e3504 0 1544165240000 4 connected
a6d4cb574131b82d95f58c92c9fe5389dcb16f59 127.0.0.1:6383@16383 slave a798db2f4e6a756606677bf82b0488c517402412 0 1544165239936 5 connected
7bb6e7b6b77db35a306ff932a8a70277763e3504 127.0.0.1:6379@16379 myself,master - 0 1544165240000 1 connected 0-5460
d984d502c61d2b3d64b0100a0179642d92c9f95d 127.0.0.1:6384@16384 slave 292362ebc26df9920de8e8c19fdad0d9a5e05fb7 0 1544165241941 6 connected
a798db2f4e6a756606677bf82b0488c517402412 127.0.0.1:6380@16380 master - 0 1544165239000 2 connected 5461-10922
292362ebc26df9920de8e8c19fdad0d9a5e05fb7 127.0.0.1:6381@16381 master - 0 1544165241000 3 connected 10923-16383

 

可以看到使用的是3主3從的配置,虛擬槽的分配是0-5460、5461-10922、10923-16383,我們來演示下這個異常。。

127.0.0.1:6379> set a b
(error) MOVED 15495 127.0.0.1:6381

可以看到,key為a的時候應該將數據插入到15495的槽內。但是15495這個槽是分配在端口號為6381的這個節點上。當嘗試插入操作的時候返回了moved異常,異常信息包括目標節點和槽的信息。
要直接通過redis-cli 登錄插入可以使用 -c 選項,-c為以集群模式登錄

[root@192.168.118.15 ~]#redis-cli -h 127.0.0.1 -p 6379 -c
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 127.0.0.1:6381
OK
127.0.0.1:6381> keys *
1) "a"

 

 

【消息機制】

redis cluster 集群中通過消息來進行通信。消息共有以下5種:

meet消息:發送者會向接受者發送cluster meet命令,請求接受者將發送者加入到集群中。所謂的無中心網絡結構就是使用meet命令構建的。
ping消息:集群中的每個節點每秒鍾都會從已知節點列表選舉出5個節點,然后從這5個節點中選中一個最長時間沒有發送ping消息的節點作為目標節點來發送ping消息,來檢測目標節點是否處於在線狀態。
pong消息:接受者接受到發送者發送的meet消息或者ping消息后,會回復pong消息,用於確認消息已經到達。另外,pong消息也可以用於刷新接收者對發送者的信息,例如故障轉移后,從節點會向集群中發送pong消息,用於告知從節點已經升級為主節點。
fail消息:fail消息用於通知將某個節點置為下線狀態。例如節點A認為節點B已下線,節點A會向集群中發送一條fail消息,接受到這條消息的節點會將節點B標記為已 下線。
publish消息:當某個節點收到publish命令后,會向集群中發送一條publish消息。

 

【故障檢測】

集群中的每個節點都會定期地向集群中其它節點發送ping消息,以此來檢測對方是否在線。如果在規定時間內沒有收到pong回復。則認為目標節點標記為疑似下線(PFAIL)。
如果集群中的半數異常(大於等於N/2 + 1)的主節點認為某個節點A疑似下線(PFAIL),那么這個節點A將被標記為已下線(FAIL)。將節點標記A為已下線的節點會向集群發送一條關於節點A顯現的消息,所有收到這條F消息的節點都會立即將主節點A標記為已下線。
舉個例子,在下圖所示中,主節點7002和主節點7003都認為主節點7000進入了下線狀態。並且主節點7001也認為主節點7000進入了下線狀態。綜合起來,在集群中4個主節點里面,有3個都將主節點7000標記為下線。所以主節點7001會將7000節點標記為已下線。並向集群中廣播一條關於主節點7000的FAIL消息,如下圖所示。

 

【故障轉移】

當一個從節點發現自己正在復制的主節點進入了已下線時,從節點將開始對已下線的主節點進行故障轉移操作,以下是故障轉移的執行步驟:

  1. 下線的主節點的所有從節點里面會進行選舉,選舉出一個新的主節點;
  2. 被選中的從節點會執行 slave no one命令,成為新的主節點;
  3. 新的主節點會撤銷所有對已下線主節點的槽指派,並將這些槽指派給自己;
  4. 新的主節點向集群廣播一條pong消息,這條pong消息可以讓集群中的其他節點立即知道這個節點已經由從節點變成了主節點,並且這個主節點已經接管了原本由已下線節點處理的槽。
  5. 新的主節點開始接受和自己負責處理的槽有關的命令請求,故障轉移操作完成。

 

模擬redis cluster 節點服務掛掉后,slave切換為主節點

[root@192.168.118.15 ~]#redis-cli -h 127.0.0.1 -p 6379 -c
127.0.0.1:6379> cluster nodes
fd583297b826fc92bc872d5a3a6e8bfda30a5eda 127.0.0.1:6382@16382 slave 7bb6e7b6b77db35a306ff932a8a70277763e3504 0 1544166906000 4 connected
a6d4cb574131b82d95f58c92c9fe5389dcb16f59 127.0.0.1:6383@16383 slave a798db2f4e6a756606677bf82b0488c517402412 0 1544166907000 5 connected
7bb6e7b6b77db35a306ff932a8a70277763e3504 127.0.0.1:6379@16379 myself,master - 0 1544166904000 1 connected 0-5460
d984d502c61d2b3d64b0100a0179642d92c9f95d 127.0.0.1:6384@16384 slave 292362ebc26df9920de8e8c19fdad0d9a5e05fb7 0 1544166905995 6 connected
a798db2f4e6a756606677bf82b0488c517402412 127.0.0.1:6380@16380 master - 0 1544166906000 2 connected 5461-10922
292362ebc26df9920de8e8c19fdad0d9a5e05fb7 127.0.0.1:6381@16381 master - 0 1544166907998 3 connected 10923-16383

集群中3個master、3個slave 狀態都為:connected

[root@192.168.118.15 ~]#redis-cli -h 127.0.0.1 -p 6380 shutdown  # down掉其中一個master節點

127.0.0.1:6379> cluster nodes
fd583297b826fc92bc872d5a3a6e8bfda30a5eda 127.0.0.1:6382@16382 slave 7bb6e7b6b77db35a306ff932a8a70277763e3504 0 1544166994224 4 connected
a6d4cb574131b82d95f58c92c9fe5389dcb16f59 127.0.0.1:6383@16383 master - 0 1544166992000 7 connected 5461-10922    # 為做 6380 的從節點已經切換為master
7bb6e7b6b77db35a306ff932a8a70277763e3504 127.0.0.1:6379@16379 myself,master - 0 1544166993000 1 connected 0-5460
d984d502c61d2b3d64b0100a0179642d92c9f95d 127.0.0.1:6384@16384 slave 292362ebc26df9920de8e8c19fdad0d9a5e05fb7 0 1544166992218 6 connected
a798db2f4e6a756606677bf82b0488c517402412 127.0.0.1:6380@16380 master,fail - 1544166962530 1544166959000 2 disconnected    # 狀態為: fail
292362ebc26df9920de8e8c19fdad0d9a5e05fb7 127.0.0.1:6381@16381 master - 0 1544166993220 3 connected 10923-16383

 

 

注意:如果集群超過半數以上(6個服務down超過3個服務)master掛掉,無論是否有slave,集群進入fail狀態.

 

python 連接 Redis Cluster 方式

#!/usr/bin/python
# rediscluster包需要python安裝 pip install redis-py-cluster

from rediscluster import StrictRedisCluster


redis_nodes = [{'host': '192.168.118.15', 'port': 6379},
               {'host': '192.168.118.15', 'port': 6380},
               {'host': '192.168.118.15', 'port': 6381},
               {'host': '192.168.118.15', 'port': 6382},
               {'host': '192.168.118.15', 'port': 6383},
               {'host': '192.168.118.15', 'port': 6384}]

redisconn = StrictRedisCluster(startup_nodes=redis_nodes)

#redisconn.set('name', 'hkey')    # 插入數據
#redisconn.set('age', 20)    # 插入數據
#for i in range(10000):    # 循環插入數據
#    redisconn.set(i, 'Test')
print(redisconn.get('name'))    # 獲取數據
print(redisconn.get('age'))        # 獲取數據

 

 

或者通過 Redis Desktop Manager 連接:

 


免責聲明!

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



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