前言
Redis Cluster 與 Redis Master-Slave 架構的差異
Redis Master-Slave
每個 Node 是包含所有資料,Slave 只是分擔讀取功能、failover 可快速替換 Master 的功能
而 Master 仍承受巨量寫入的壓力,且需要另建 Sentinel 來操作 failover
Redis Cluster
自帶 Sentinel 無需額外建立,且透過 Sharding 來將資料分散寫入到各個 Cluster Node 中,分散壓力
本篇透過建立 6 台 Redis 服務,組成 3 個 Master、3 個 Slave 架構的 Redis Cluster
並測試 faileover、節點縮容、節點擴充的流程
環境
Linux VM = ubuntu-2004-lts
Redis Docker映像檔 = redis:6.0.0
VPC、Firewall 建置參考w4560000 - Redis Master-Slave 設定 VPC & Firewall
機器 | IP |
---|---|
redis-1 | 10.140.0.11 |
redis-2 | 10.140.0.12 |
redis-3 | 10.140.0.13 |
redis-4 | 10.140.0.14 |
redis-5 | 10.140.0.15 |
redis-6 | 10.140.0.16 |
設定 VM
建立 6 台 Redis 機器
for i in 1 2 3 4 5 6; do
gcloud compute instances create redis-${i} \
--async \
--boot-disk-size 100GB \
--can-ip-forward \
--image-family ubuntu-2004-lts \
--image-project ubuntu-os-cloud \
--machine-type e2-standard-2 \
--private-network-ip 10.240.0.1${i} \
--scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \
--subnet redis-vpc-subnet \
--zone asia-east1-a \
--tags redis-vpc
done
安裝 Docker
參考 w4560000 - Linux 安裝 Docker、Docker-Compose
6 台 VM 都先設定好 volumn 資料夾
mkdir redis && mkdir redisdata
建置 Redis Cluster
新增 redisTemplate.conf
cluster-enabled <yes/no>
是否啟動 redis cluster
ex: cluster-enabled yescluster-config-file
redis cluster 設定檔名,紀錄狀態設定 (使用者無法編輯)
ex: cluster-config-file nodes.confcluster-node-timeout
當 master 在該時間內,沒有回應其他 node 則會執行 failover,將它的 slave 升為新的 master
ex: cluster-node-timeout 15000cluster-replica-validity-factor
若設為 0,則無論 slave 與 master 斷開連線多長時間,slave 都會嘗試在 failover 時嘗試成為 master
若設 大於 0,則可斷開連線時間 = cluster-replica-validity-factor * cluster-node-timeout (秒)
若該 slave 超過可斷開連線時間,failover 發生時,則不會被推派為 master
若 cluster-replica-validity-factor = 10、cluster-node-timeout = 5000 毫秒 = 5 秒
則可斷開連線時間 = 50 秒,slave 超過 50 秒沒有與 master 連線,則喪失成為 master 的機會
ex: cluster-replica-validity-factor 10cluster-announce-ip
當前 cluster-node 的 IP
ex: cluster-announce-ip 10.140.0.11cluster-announce-port
當前 cluster-node 的 Port
ex: cluster-announce-port 6379cluster-announce-bus-port
當前 cluster-node 用來與其他 cluster-node 同步資訊、檢測故障的 Port
ex: cluster-announce-bus-port 16379repl-ping-replica-period
master 每隔幾秒會 ping slave,確認是否活著
ex: repl-ping-replica-period 10 (預設)repl-timeout、repl-ping-replica-period 說明參考 w4560000 - Redis Master-Slave
在 cluster,repl-timeout 觸發時不會發生 failover,而是由 cluster-node-timeout 在控制 failover
redis-1 ~ redis-6
路徑 ~/redis/redisTemplate.conf
bind 0.0.0.0
protected-mode no
dir ./
# Cluster
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-replica-validity-factor 10
cluster-announce-ip ${IP}
cluster-announce-port 6379
cluster-announce-bus-port 16379
# AOF
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
# AOF rewrite
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 0
auto-aof-rewrite-min-size 1mb
aof-load-truncated no
aof-use-rdb-preamble yes
# REPLICATION
repl-ping-replica-period 10
repl-timeout 60
新增 redis.conf
redis-1 ~ redis-6
路徑 ~/redis/redis.conf
IP=$(hostname -i) envsubst < ./redis/redisTemplate.conf > ./redis/redis.conf
建置 Redis cluster
啟動 Redis 服務
redis-1 ~ redis-6
docker run --name redis \
-p 6379:6379 \
-p 16379:16379 \
-v /home/leozheng0629/redis:/usr/local/etc/redis \
-v /home/leozheng0629/redisdata:/data \
-d redis:6.0.0 \
redis-server /usr/local/etc/redis/redis.conf
建立 Cluster
docker exec -it redis redis-cli --cluster create 10.240.0.11:6379 10.240.0.12:6379 10.240.0.13:6379 10.240.0.14:6379 10.240.0.15:6379 10.240.0.16:6379 --cluster-replicas 1
# 輸出
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 10.240.0.15:6379 to 10.240.0.11:6379
Adding replica 10.240.0.16:6379 to 10.240.0.12:6379
Adding replica 10.240.0.14:6379 to 10.240.0.13:6379
M: aefdddbe65c8105c47b545bab901578c7a92f2f9 10.240.0.11:6379
slots:[0-5460] (5461 slots) master
M: 23808824f980269c05af462dbc3b82b5ab63995d 10.240.0.12:6379
slots:[5461-10922] (5462 slots) master
M: bae34725dfd1fb24f4ea6c9464a5d2c7e56db445 10.240.0.13:6379
slots:[10923-16383] (5461 slots) master
S: d3b65dce1ca8befabd8c929b7481970ac892e6ac 10.240.0.14:6379
replicates bae34725dfd1fb24f4ea6c9464a5d2c7e56db445
S: b46f42b32e50918480923dcee3f13201f2b5fde4 10.240.0.15:6379
replicates aefdddbe65c8105c47b545bab901578c7a92f2f9
S: 4436d2bf76ec3bc754acc7df8284e8fd87dd0f08 10.240.0.16:6379
replicates 23808824f980269c05af462dbc3b82b5ab63995d
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 10.240.0.11:6379)
M: aefdddbe65c8105c47b545bab901578c7a92f2f9 10.240.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: bae34725dfd1fb24f4ea6c9464a5d2c7e56db445 10.240.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 23808824f980269c05af462dbc3b82b5ab63995d 10.240.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: d3b65dce1ca8befabd8c929b7481970ac892e6ac 10.240.0.14:6379
slots: (0 slots) slave
replicates bae34725dfd1fb24f4ea6c9464a5d2c7e56db445
S: b46f42b32e50918480923dcee3f13201f2b5fde4 10.240.0.15:6379
slots: (0 slots) slave
replicates aefdddbe65c8105c47b545bab901578c7a92f2f9
S: 4436d2bf76ec3bc754acc7df8284e8fd87dd0f08 10.240.0.16:6379
slots: (0 slots) slave
replicates 23808824f980269c05af462dbc3b82b5ab63995d
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
備註 Port 除了 6379 外,cluster-announce-bus-port 設定的 16379 也要開通
cluster-announce-bus-port 是 cluster 之間用來做故障檢測、failover、設定更新的 Port
若 16379 沒開通,cluster create 時會一直卡在 Waiting for the cluster to join,無法順利建置
建置好後確認一下 cluster 狀態
docker exec -it redis redis-cli cluster nodes
# 輸出
bae34725dfd1fb24f4ea6c9464a5d2c7e56db445 10.240.0.13:6379@16379 master - 0 1688031261897 3 connected 10923-16383
23808824f980269c05af462dbc3b82b5ab63995d 10.240.0.12:6379@16379 master - 0 1688031258000 2 connected 5461-10922
d3b65dce1ca8befabd8c929b7481970ac892e6ac 10.240.0.14:6379@16379 slave bae34725dfd1fb24f4ea6c9464a5d2c7e56db445 0 1688031260000 4 connected
b46f42b32e50918480923dcee3f13201f2b5fde4 10.240.0.15:6379@16379 slave aefdddbe65c8105c47b545bab901578c7a92f2f9 0 1688031259890 5 connected
aefdddbe65c8105c47b545bab901578c7a92f2f9 10.240.0.11:6379@16379 myself,master - 0 1688031260000 1 connected 0-5460
4436d2bf76ec3bc754acc7df8284e8fd87dd0f08 10.240.0.16:6379@16379 slave 23808824f980269c05af462dbc3b82b5ab63995d 0 1688031260894 6 connected
docker exec -it redis redis-cli 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:603
cluster_stats_messages_pong_sent:652
cluster_stats_messages_sent:1255
cluster_stats_messages_ping_received:647
cluster_stats_messages_pong_received:603
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:1255
Redis Clsuter 新增查詢 Key 備註
當 cluster 建立好後,要查詢或操作時,要透過 cluster 模式進入 (redis-cli -c)
docker exec -it redis redis-cli -c Set Key1 "1"
# 輸出
OK
# 若沒透過 cluster 模式 則會無法操作,因 Redis cluster 是透過計算 Key 的 Hash 值來判斷要存到哪個 redis node 中
# 若沒加上 -c,則只能查該台 redis 資料
docker exec -it redis redis-cli Get Key1
# 輸出
(error) MOVED 15360 10.240.0.13:6379
設定測試資料
先計算出 Key 的 Slot
docker exec -it redis redis-cli cluster keyslot Key1
# 輸出
(integer) 5291
docker exec -it redis redis-cli cluster keyslot Key2
# 輸出
(integer) 9416
docker exec -it redis redis-cli cluster keyslot Key3
# 輸出
(integer) 13545
確認Key可以分散到各個Node後,再來設定Key
docker exec -it redis redis-cli -c Set Key1 "1"
docker exec -it redis redis-cli -c Set Key2 "2"
docker exec -it redis redis-cli -c Set Key3 "3"
設定後再次確認Key分布在三個Node上
docker exec -it redis redis-cli --cluster check 10.240.0.11:6379
# 輸出
10.240.0.11:6379 (aefdddbe...) -> 1 keys | 5461 slots | 1 slaves.
10.240.0.13:6379 (bae34725...) -> 1 keys | 5461 slots | 1 slaves.
10.240.0.12:6379 (23808824...) -> 1 keys | 5462 slots | 1 slaves.
[OK] 3 keys in 3 masters.
...
目前 Reids Cluster 配置
master | slave | slot | Keys |
---|---|---|---|
10.240.0.11 (m1) | 10.240.0.15 (s1) | 0-5460 (共有5461) | Key1 |
10.240.0.12 (m2) | 10.240.0.16 (s2) | 5461-10922 (共有5462) | Key2 |
10.240.0.13 (m3) | 10.240.0.14 (s3) | 10923-16383 (共有5461) | Key3 |
查看 Cluster slot
docker exec -it redis redis-cli -c CLUSTER SLOTS
縮容 Redis Cluster Node
目標: 將 m3、s3 移出 Redis Cluster
將 m3 的 Slot 重新分配給 m1、m2
原本 m3 有 5461 個 Slot,先全部分配給 m1,再透過 redis-cli rebalance 自動平均 SLOT (這樣就不用自行計算要分配多少 SLOT 給各個 Node)
# redis-cli --cluster reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes
# redis-cli --cluster reshard <要移除的Redis IP>:<要移除的Redis Port> --cluster-from <要移除的Redis ID> --cluster-to <要遷移的Redis IP> --cluster-slots <Slot數量> --cluster-yes
# 分給 m1
docker exec -it redis redis-cli --cluster reshard 10.240.0.13:6379 --cluster-from bae34725dfd1fb24f4ea6c9464a5d2c7e56db445 --cluster-to aefdddbe65c8105c47b545bab901578c7a92f2f9 --cluster-slots 5461 --cluster-yes
# 重新分配 SLOT
docker exec -it redis redis-cli --cluster rebalance 10.240.0.11:6379
分配好後再次確認目前SLOT
docker exec -it redis redis-cli --cluster check 10.240.0.11:6379
# 輸出
10.240.0.11:6379 (aefdddbe...) -> 2 keys | 8192 slots | 1 slaves.
10.240.0.13:6379 (bae34725...) -> 0 keys | 0 slots | 1 slaves.
10.240.0.12:6379 (23808824...) -> 1 keys | 8192 slots | 1 slaves.
...
m3 的 SLOT 已被分配給 m1、m2
將 m3、s3 移出 Redis Cluster
# redis-cli --cluster del-node <host>:<port> <node-id>
# redis-cli --cluster del-node <要移除的Redis IP>:<要移除的Redis Port> <要移除的Redis ID>
# 移除 m3
docker exec -it redis redis-cli --cluster del-node 10.240.0.13:6379 bae34725dfd1fb24f4ea6c9464a5d2c7e56db445
# 移除 s3
docker exec -it redis redis-cli --cluster del-node 10.240.0.14:6379 d3b65dce1ca8befabd8c929b7481970ac892e6ac
移除後確認 Cluster Node
docker exec -it redis redis-cli cluster nodes
# 輸出
aefdddbe65c8105c47b545bab901578c7a92f2f9 10.240.0.11:6379@16379 myself,master - 0 1690628923000 13 connected 2730-5460 10923-16383
b46f42b32e50918480923dcee3f13201f2b5fde4 10.240.0.15:6379@16379 slave 23808824f980269c05af462dbc3b82b5ab63995d 0 1690628921296 14 connected
23808824f980269c05af462dbc3b82b5ab63995d 10.240.0.12:6379@16379 master - 0 1690628924309 14 connected 0-2729 5461-10922
4436d2bf76ec3bc754acc7df8284e8fd87dd0f08 10.240.0.16:6379@16379 slave aefdddbe65c8105c47b545bab901578c7a92f2f9 0 1690628923304 13 connected
移除 m3、s3 後剩下 m1、s1、m2、s2,而原本在 m3 的 Key3 也被轉移給 m1 了
擴充 Redis Cluster Node
目標: 將 m3、s3 重新加入 Redis Cluster
將 m3、s3 加入 Redis Cluster
# redis-cli --cluster add-node <new-host>:<new-port> <old-host>:<old-host>
# redis-cli --cluster add-node <要加入的Redis IP>:<要加入的Redis Port> <已存在的Redis IP>:<已存在的Reids Port>
# 將 m3 加入 Redis Cluster
docker exec -it redis redis-cli --cluster add-node 10.240.0.13:6379 10.240.0.11:6379
# 將 s3 加入 Redis Cluster,並且為 m3 的 Slave
docker exec -it redis redis-cli --cluster add-node 10.240.0.14:6379 10.240.0.11:6379 --cluster-slave --cluster-master-id bae34725dfd1fb24f4ea6c9464a5d2c7e56db445
確認目前 Cluster 配置
docker exec -it redis redis-cli --cluster check 10.240.0.11:6379
# 輸出
10.240.0.11:6379 (aefdddbe...) -> 2 keys | 8192 slots | 1 slaves.
10.240.0.13:6379 (bae34725...) -> 0 keys | 0 slots | 1 slaves.
10.240.0.12:6379 (23808824...) -> 1 keys | 8192 slots | 1 slaves.
...
確認 m3、s3 已被加回 Cluster
m1、m2、m3 重新分配 SLOT
# 將目前 cluster Node 的 SLOT,分配給 m3
docker exec -it redis redis-cli --cluster reshard 10.240.0.11:6379 --cluster-from all --cluster-to bae34725dfd1fb24f4ea6c9464a5d2c7e56db445 --cluster-slots 5461 --cluster-yes
分配完後確認目前 Cluster 配置
docker exec -it redis redis-cli --cluster check 10.240.0.11:6379
# 輸出
10.240.0.11:6379 (aefdddbe...) -> 1 keys | 5461 slots | 1 slaves.
10.240.0.13:6379 (bae34725...) -> 1 keys | 5462 slots | 1 slaves.
10.240.0.12:6379 (23808824...) -> 1 keys | 5461 slots | 1 slaves.
...
重新分配過後的 SLOT 分布
docker exec -it redis redis-cli --cluster node
# 輸出
aefdddbe65c8105c47b545bab901578c7a92f2f9 10.240.0.11:6379@16379 myself,master - 0 1690631611000 26 connected 10923-16383
b46f42b32e50918480923dcee3f13201f2b5fde4 10.240.0.15:6379@16379 slave 23808824f980269c05af462dbc3b82b5ab63995d 0 1690631611006 27 connected
bae34725dfd1fb24f4ea6c9464a5d2c7e56db445 10.240.0.13:6379@16379 master - 0 1690631612010 28 connected 0-2729 2731-3640 5461-7281
23808824f980269c05af462dbc3b82b5ab63995d 10.240.0.12:6379@16379 master - 0 1690631610004 27 connected 2730 3641-5460 7282-10922
d3b65dce1ca8befabd8c929b7481970ac892e6ac 10.240.0.14:6379@16379 slave aefdddbe65c8105c47b545bab901578c7a92f2f9 0 1690631614019 26 connected
4436d2bf76ec3bc754acc7df8284e8fd87dd0f08 10.240.0.16:6379@16379 slave bae34725dfd1fb24f4ea6c9464a5d2c7e56db445 0 1690631613015 28 connected
參考文件
HackMD tienyulin - Redis (六) - 主從複製、哨兵與叢集模式#叢集模式
CSDN 大话JAVA的那些事 - 二、redis.conf文件详解
石頭的coding之路 - Redis Cluster 介紹
TPIU - Docker + Redis Cluster 實戰
ITpub博客 壹頁書 - Redis主从复制网络闪断处理
博客園 一见 - redis的repl-ping-slave-period和repl-ping-replica-period
博客園 一见 - Redis集群的主从切换研究
Redis 官方文件 - Scaling with Redis Cluster
Baeldung - Redis Sentinel vs Clustering
微信公眾號 SH的全栈笔记 - 深度图解Redis Cluster原理
轉載請註明來源,若有任何錯誤或表達不清楚的地方,歡迎在下方評論區留言,也可以來信至 leozheng0621@gmail.com
如果文章對您有幫助,歡迎斗內(donate),請我喝杯咖啡