一、理論相關
-
透過上篇部落格:搭建Redis“主-從-從”模式叢集並使用 RedisTemplate 實現讀寫分離,我們已經搭建好了Redis“主-從-從”模式叢集並且實現讀寫分離,這裡會出現幾個問題:如果主庫當機了,我們就需要執行一個新主庫,比如說把一個從庫切換為主庫,把它當成主庫。這就會涉及到三個問題:
- 主庫真的掛了嗎?
- 該選擇哪個從庫作為主庫?
- 怎麼把新主庫的相關資訊通知給從庫和客戶端呢?
-
由此,我們便引出哨兵機制:
1、哨兵機制:主庫掛了,如何不間斷服務?
1.1、哨兵機制的基本流程
一個執行在特殊模式下的Redis程序,主從庫例項執行的同時,它也在執行。主要負責三個任務:
-
監控 - 需要判斷主庫是否處於下線狀態
- 哨兵程序在執行時,週期性地給所有的主從庫傳送PING命令,檢測它們是否仍線上執行
- 從庫沒有在規定時間內響應哨兵的PING命令(對PING命令響應超時),標記為“下線狀態”
- 主庫對PING命令響應超時,判定主庫下線,開始自動切換主庫的流程
-
選主(選擇主庫) - 決定哪個從庫例項作為主庫
- 主庫掛了以後,從很多個從庫裡,按照一定的規則選擇一個從庫例項,把它作為新的主庫
-
通知
- 把新主庫的連線資訊發給其它從庫,執行
replicaof
命令,和新主庫建立連線,並進行資料複製 - 把新主庫的連線資訊通知給客戶端,讓它們把請求操作發到新主庫
- 把新主庫的連線資訊發給其它從庫,執行
1.2、主觀下線和客觀下線
主庫:特別注意哨兵誤判的情況 - 主庫實際沒有下線,哨兵誤以為下線了
- 一般發生在叢集網路壓力較大、網路擁塞,或主庫本身壓力較大的情況
- 避免後續沒有價值的開銷
解決方法:
- 多例項組成的叢集模式進行部署 - 哨兵叢集
- 引入多個哨兵例項一起判斷,降低誤判率
- 只有大多數哨兵例項都判斷主庫已經“主觀下線”,主庫才會被標記為“客觀下線”
- 當有 N 個哨兵例項時,最好要有 N/2 + 1 個例項判斷主庫為“主觀下線”,才能最終判定主庫為“客觀下線”
- 有多少個例項做出“主觀下線”的判斷才可以 - 可以由 Redis 管理員自行設定
1.3、如何選定新主庫?
-
篩選 + 打分
- 在多個從庫中,先按照一定的篩選條件,把不符合條件的從庫去掉
- 再按照一定的規則,給剩下的從庫逐個打分,將得分最高的從庫選為新主庫
-
篩選條件
- 線上狀態
- 網路連線狀態
- 配置項down-after-milliseconds * 10
- down-after-milliseconds:認定主從庫斷連的最大連線超時時間
- 如果在 down-after-milliseconds 毫秒內,主從節點都沒有透過網路聯絡上,就可以認為主從節點斷連了
- 發生斷連的次數超過10次,這個從庫的網路狀況不好,不適合作為新主庫
-
打分(在某一輪中,從庫得分最高,它就是主庫,選主過程結束;否則進行下一輪打分)
- 從庫優先順序(優先順序最高的從庫得分高)
- 配置項slave-priority,給不同從庫設定不同優先順序
- 比如:兩個從庫中記憶體大的例項設定高優先順序
- 從庫複製進度(和舊主庫同步程度最接近的從庫得分高)
- 如果選擇和舊主庫同步最接近的那個從庫作為主庫,這個新主庫上就會有最新的資料
- slave_repl_offset最接近master_repl_offset
- 從庫ID號(ID號小的從庫得分高)
- 預設規定
1.4、小結
-
組成哨兵機制可以解決主庫之間切換服務的問題,但同樣的,引入哨兵機制就相當於再引入例項,那麼我們又會面臨一些問題:
- 哨兵叢集中有例項掛了,怎麼辦,會影響主庫狀態判斷和選主嗎?
- 哨兵叢集多數例項達成共識,判斷出主庫“客觀下線”後,由哪個例項來執行主從切換呢?
-
那麼接下來,我們就引出哨兵叢集的概念:
2、哨兵叢集:哨兵掛了,主從庫還能切換嗎?
- 一旦多個例項組成了哨兵叢集,即使有哨兵例項出現故障掛掉了,其他哨兵還能繼續協作完成主從庫切換的工作,包括判定主庫是不是處於下線狀態,選擇新主庫,以及通知從庫和客戶端。
2.1、基於pub/sub機制的哨兵叢集組成
- 同時,它也可以從主庫上訂閱訊息,獲得其他哨兵釋出的連線資訊
- 除了哨兵例項,我們自己編寫的應用程式也可以透過 Redis 進行訊息的釋出和訂閱
頻道:訊息的類別
- 哨兵除了彼此間建立連線形成叢集,還需要和從庫建立連線
- 在哨兵的監控任務中,需要對主從庫都進行心跳判斷,而且在主從庫切換完成後,需要通知從庫,讓它們和新主庫同步
- 主從庫切換後,客戶端也需要知道新主庫的連線資訊,才能向新主庫傳送請求操作
- 哨兵還需要把新主庫的資訊告訴客戶端
- 客戶端需要獲取到哨兵叢集在監控、選主、切換這個過程中發生的各種事件
2.2、基於pub/sub機制的客戶端事件通知
- 從本質上說,哨兵就是一個執行在特定模式下的 Redis 例項,只不過它並不服務請求操作,只是完成監控、選主和通知的任務。
- 每個哨兵例項也提供pub/sub機制
操作步驟:
- 客戶端讀取哨兵的配置檔案
- 獲得哨兵的地址和埠,和哨兵建立網路連線
- 在客戶端執行訂閱命令,獲取不同的事件訊息
SUBSCRIBE +odown
PSUBSRCIBE *
switch-master <master name> <oldip> <oldport> <newip> <newport>
- 表示主庫已經切換,新主庫的IP地址和埠資訊已經有了
- 客戶端不僅可以在主從切換後得到新主庫的連線資訊,還可以監控到主從庫切換過程中發生的各個重要事件
- 客戶端就可以知道主從切換進行到哪一步,有助於瞭解切換進度
2.3、由哪個哨兵執行主從切換?
- “投票仲裁”過程
在投票過程中,任何一個想成為 Leader 的哨兵,要滿足兩個條件:
- 拿到半數以上的贊成票
- 拿到的票數同時還需要大於等於哨兵配置檔案中的 quorum 值
3個哨兵、quorum為2的選舉過程:
時間 | 哨兵1(S1) | 哨兵2(S2) | 哨兵3(S3) |
---|---|---|---|
T1 | 判斷主庫為“客觀下線”,給自己投1票Y,向S2、S3發投票請求,表示要成為Leader | ||
T2 | 判斷主庫為“客觀下線”,給自己投1票Y,向S1、S3發投票請求,表示要成為Leader | ||
T3 | 收到S3的請求,回覆N(已經給自己投了一票Y,不能再給其它哨兵投Y) | 收到S3的請求,回覆Y | |
T4 | 收到S1的請求,回覆N(網路傳輸可能擁塞了,導致投票請求傳輸慢了) | ||
T5 | 1票Y,1票N | 2票Y,成為Leader |
- 如果S3沒有拿到2票Y,這輪投票就不會產生Leader,哨兵叢集會等待一段時間(也就是哨兵故障轉移超時時間的 2 倍),再重新選舉。
- 如果哨兵叢集只有 2 個例項,此時,一個哨兵要想成為 Leader,必須獲得 2 票,而不是 1 票。所以,如果有個哨兵掛掉了,那麼,此時的叢集是無法進行主從庫切換的。因此,通常我們至少會配置 3 個哨兵例項。
2.4、小結
哨兵叢集的關鍵機制:
- 基於 pub/sub 機制的哨兵叢集組成過程;
- 基於 INFO 命令的從庫列表,這可以幫助哨兵和從庫建立連線;
- 基於哨兵自身的 pub/sub 功能,這實現了客戶端和哨兵之間的事件通知。
- 要保證所有哨兵例項的配置是一致的,尤其是主觀下線的判斷值 down-after-milliseconds。
- 可能會因為這個值在不同的哨兵例項上配置不一致,導致哨兵叢集一直沒有對有故障的主庫形成共識,也就沒有及時切換主庫,最終的結果就是叢集服務不穩定。
二、實踐
執行環境:虛擬機器作業系統:centOS7,IP地址:192.168.88.130
centOS 環境下已經安裝好了 docker 和 docker-compose
Windows 環境下已經安裝好了 redis-cli.exe 工具(用來檢視哨兵叢集狀態)
採用Redis:7.4.0
在上一篇博文中,我們搭建了Redis主從庫叢集,結構如下:
[root@centos redis-cluster]# find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'
.
|____docker-compose.yml
|____redis0
| |____data
| | |____dump.rdb
| |____redis.conf
|____redis1
| |____data
| | |____dump.rdb
| |____redis.conf
|____redis2
| |____data
| | |____dump.rdb
| |____redis.conf
|____redis3
| |____data
| | |____dump.rdb
| |____redis.conf
|____redis4
| |____data
| | |____dump.rdb
| |____redis.conf
-
其中,
redis0
為主庫,redis1
、redis2
分別為從庫I、從庫II;redis3
、redis4
分別為從庫II的從庫1和從庫2 -
接下來,我們在該結構的基礎上,搭建
sentinel
哨兵叢集
-
首先,我們先看看上一次搭建叢集的
redis.conf
:redis0/redis.conf
protected-mode no bind 0.0.0.0 save 900 1 save 300 10 save 60 10000 rdbcompression yes dbfilename dump.rdb dir /data # 關閉 aof 日誌備份 appendonly no # 自定義密碼 requirepass root # 啟動埠 port 6379 # 換成自己的虛擬機器的IP replica-announce-ip 192.168.88.130
redis1/redis.conf
protected-mode no bind 0.0.0.0 save 900 1 save 300 10 save 60 10000 rdbcompression yes dbfilename dump.rdb dir /data # 關閉 aof 日誌備份 appendonly no # 啟動埠 port 6479 # 將當前 redis 作為 redis0 的 slave # 由於 docker 使用 host 模式,使用的是宿主機的 ip replicaof 192.168.88.130 6379 # 自定義密碼 requirepass root # 訪問 master 節點時需要提供的密碼 masterauth root masteruser redis0 replica-announce-ip 192.168.88.130
redis2/redis.conf
protected-mode no bind 0.0.0.0 save 900 1 save 300 10 save 60 10000 rdbcompression yes dbfilename dump.rdb dir /data # 關閉 aof 日誌備份 appendonly no # 啟動埠 port 6579 # 將當前 redis 作為 redis0 的 slave # 由於 docker 使用 host 模式,使用的是宿主機的 ip replicaof 192.168.88.130 6379 # 自定義密碼 requirepass root # 訪問 master 節點時需要提供的密碼 masterauth root replica-announce-ip 192.168.88.130
redis3/redis.conf
protected-mode no bind 0.0.0.0 save 900 1 save 300 10 save 60 10000 rdbcompression yes dbfilename dump.rdb dir /data # 關閉 aof 日誌備份 appendonly no # 啟動埠 port 6679 # 將當前 redis 作為 redis2 的 slave # 由於 docker 使用 host 模式,使用的是宿主機的 ip replicaof 192.168.88.130 6579 # 自定義密碼 requirepass root # 訪問 master 節點時需要提供的密碼 masterauth root replica-announce-ip 192.168.88.130
redis4/redis.conf
protected-mode no bind 0.0.0.0 save 900 1 save 300 10 save 60 10000 rdbcompression yes dbfilename dump.rdb dir /data # 關閉 aof 日誌備份 appendonly no # 啟動埠 port 6779 # 將當前 redis 作為 redis2 的 slave # 由於 docker 使用 host 模式,使用的是宿主機的 ip replicaof 192.168.88.130 6579 # 自定義密碼 requirepass root # 訪問 master 節點時需要提供的密碼 masterauth root replica-announce-ip 192.168.88.130
1、搭建sentinel
- 新建目錄
[root@centos redis-cluster]# mkdir sentinel1
[root@centos redis-cluster]# mkdir sentinel2
[root@centos redis-cluster]# mkdir sentinel3
[root@centos redis-cluster]# mkdir sentinel1/data
[root@centos redis-cluster]# mkdir sentinel2/data
[root@centos redis-cluster]# mkdir sentinel3/data
- 編輯
sentinel.conf
[root@centos redis-cluster]# vi sentinel1/sentinel.conf
port 26379
protected-mode no
# 虛擬機器會有多個 ip,這裡指定具體一個 ip 地址
sentinel announce-ip 192.168.88.130
# 配置監控的叢集主節點的 ip 和 埠
# 如果有 2 個 sentinel 節點認為主節點主觀下線,
# 則主節點就被認為是客觀下線
# redis 的叢集名稱可以隨意配置,這裡配置為 jobs
sentinel monitor jobs 192.168.88.130 6379 2
# sentinel 會向叢集中的節點定期傳送心跳檢測命令,
# 如果在配置時間(毫秒)內沒有響應回覆,則被認為是主觀下線
sentinel down-after-milliseconds jobs 5000
# 主備切換時,最多有多少個 slave 同時對新的 master 進行同步
sentinel parallel-syncs jobs 2
# 故障轉移的超時時間
sentinel failover-timeout jobs 60000
# 如果在 Redis 設定了密碼,這裡就需要提供訪問密碼
sentinel auth-pass jobs root
# 這裡設定訪問 sentinel 的密碼
requirepass root
# 資料儲存目錄
dir /data
[root@centos redis-cluster]# vi sentinel2/sentinel.conf
port 26479
protected-mode no
# 虛擬機器會有多個 ip,這裡指定具體一個 ip 地址
sentinel announce-ip 192.168.88.130
# 配置監控的叢集主節點的 ip 和 埠
# 如果有 2 個 sentinel 節點認為主節點主觀下線,
# 則主節點就被認為是客觀下線
# redis 的叢集名稱可以隨意配置,這裡配置為 jobs
sentinel monitor jobs 192.168.88.130 6379 2
# sentinel 會向叢集中的節點定期傳送心跳檢測命令,
# 如果在配置時間(毫秒)內沒有響應回覆,則被認為是主觀下線
sentinel down-after-milliseconds jobs 5000
# 主備切換時,最多有多少個 slave 同時對新的 master 進行同步
sentinel parallel-syncs jobs 2
# 故障轉移的超時時間
sentinel failover-timeout jobs 60000
# 如果在 Redis 設定了密碼,這裡就需要提供訪問密碼
sentinel auth-pass jobs root
# 這裡設定訪問 sentinel 的密碼
requirepass root
# 資料儲存目錄
dir /data
[root@centos redis-cluster]# vi sentinel3/sentinel.conf
port 26579
protected-mode no
# 虛擬機器會有多個 ip,這裡指定具體一個 ip 地址
sentinel announce-ip 192.168.88.130
# 配置監控的叢集主節點的 ip 和 埠
# 如果有 2 個 sentinel 節點認為主節點主觀下線,
# 則主節點就被認為是客觀下線
# redis 的叢集名稱可以隨意配置,這裡配置為 jobs
sentinel monitor jobs 192.168.88.130 6379 2
# sentinel 會向叢集中的節點定期傳送心跳檢測命令,
# 如果在配置時間(毫秒)內沒有響應回覆,則被認為是主觀下線
sentinel down-after-milliseconds jobs 5000
# 主備切換時,最多有多少個 slave 同時對新的 master 進行同步
sentinel parallel-syncs jobs 2
# 故障轉移的超時時間
sentinel failover-timeout jobs 60000
# 如果在 Redis 設定了密碼,這裡就需要提供訪問密碼
sentinel auth-pass jobs root
# 這裡設定訪問 sentinel 的密碼
requirepass root
# 資料儲存目錄
dir /data
- 然後,我們在
docker-compose.yml
新增sentinel
的配置項
[root@centos redis-cluster]# vi docker-compose.yml
services:
redis0:
image: redis
container_name: redis0
restart: always
privileged: true
network_mode: "host"
volumes:
- /root/docker/redis-cluster/redis0/data:/data
- /root/docker/redis-cluster/redis0/redis.conf:/etc/redis.conf
command:
redis-server /etc/redis.conf
redis1:
image: redis
container_name: redis1
restart: always
privileged: true
network_mode: "host"
volumes:
- /root/docker/redis-cluster/redis1/data:/data
- /root/docker/redis-cluster/redis1/redis.conf:/etc/redis.conf
command:
redis-server /etc/redis.conf
depends_on:
- redis0
redis2:
image: redis
container_name: redis2
restart: always
privileged: true
network_mode: "host"
volumes:
- /root/docker/redis-cluster/redis2/data:/data
- /root/docker/redis-cluster/redis2/redis.conf:/etc/redis.conf
command:
redis-server /etc/redis.conf
depends_on:
- redis0
redis3:
image: redis
container_name: redis3
restart: always
privileged: true
network_mode: "host"
volumes:
- /root/docker/redis-cluster/redis3/data:/data
- /root/docker/redis-cluster/redis3/redis.conf:/etc/redis.conf
command:
redis-server /etc/redis.conf
depends_on:
- redis2
redis4:
image: redis
container_name: redis4
restart: always
privileged: true
network_mode: "host"
volumes:
- /root/docker/redis-cluster/redis4/data:/data
- /root/docker/redis-cluster/redis4/redis.conf:/etc/redis.conf
command:
redis-server /etc/redis.conf
depends_on:
- redis2
sentinel1:
image: redis
container_name: sentinel1
restart: always
privileged: true
network_mode: "host"
volumes:
- /root/docker/redis-cluster/sentinel1/sentinel.conf:/etc/sentinel.conf
command:
redis-sentinel /etc/sentinel.conf
depends_on:
- redis0
sentinel2:
image: redis
container_name: sentinel2
restart: always
privileged: true
network_mode: "host"
volumes:
- /root/docker/redis-cluster/sentinel2/sentinel.conf:/etc/sentinel.conf
command:
redis-sentinel /etc/sentinel.conf
depends_on:
- redis0
sentinel3:
image: redis
container_name: sentinel3
restart: always
privileged: true
network_mode: "host"
volumes:
- /root/docker/redis-cluster/sentinel3/sentinel.conf:/etc/sentinel.conf
command:
redis-sentinel /etc/sentinel.conf
depends_on:
- redis0
- 最後,我們在
docker-compose.yml
所在目錄執行docker-compose up -d
命令啟動服務
[root@centos redis-cluster]# docker-compose up -d
[+] Running 8/8
✔ Container redis0 Running 0.0s
✔ Container redis2 Running 0.0s
✔ Container redis4 Running 0.0s
✔ Container sentinel1 Started 0.4s
✔ Container sentinel2 Started 0.4s
✔ Container sentinel3 Started 0.2s
✔ Container redis1 Running 0.0s
✔ Container redis3 Running
- 還可以透過
docker-compose ps
檢視叢集執行狀態
[root@centos redis-cluster]# docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
redis0 redis "docker-entrypoint.s…" redis0 4 days ago Up 41 minutes
redis1 redis "docker-entrypoint.s…" redis1 4 days ago Up 41 minutes
redis2 redis "docker-entrypoint.s…" redis2 4 days ago Up 41 minutes
redis3 redis "docker-entrypoint.s…" redis3 4 days ago Up 41 minutes
redis4 redis "docker-entrypoint.s…" redis4 4 days ago Up 41 minutes
sentinel1 redis "docker-entrypoint.s…" sentinel1 17 minutes ago Up 35 seconds
sentinel2 redis "docker-entrypoint.s…" sentinel2 17 minutes ago Up 17 minutes
sentinel3 redis "docker-entrypoint.s…" sentinel3 17 minutes ago Up 17 minutes
2、在Windows環境下檢視虛擬機器中搭建的哨兵狀態
- 進入到 Redis 目錄,在該目錄下開啟 cmd 命令列,執行
redis-cli.exe -h 192.168.88.130 -p 26379 -a root
- 檢視master節點的資訊
sentinel master [sentinel叢集名稱]
- 檢視除自己之外,sentinel 叢集中的其它 sentinel 節點資訊
sentinel sentinels [sentinel叢集名稱]
- 檢視slave節點的資訊
sentinel slaves [sentinel叢集名稱]
- 注:哨兵不直接支援級聯從節點的監控(即哨兵一般不會監控從節點的從節點 - 我們所搭建的redis3和redis4),最佳實踐通常是避免級聯結構,使用簡單的“主從”模式,減少管理和故障切換的複雜性。
- 因此,我們搭建的redis叢集如下:
3、模擬master節點當機
- 我們將主庫redis0停止再開機:
[root@centos redis-cluster]# docker-compose stop redis0
[+] Stopping 1/1
✔ Container redis0 Stopped 0.9s
[root@centos redis-cluster]# docker-compose start redis0
[+] Running 1/1
✔ Container redis0 Started
- 我們再在sentinel中檢視主從資訊,便會發現主庫更新,原本的redis0主庫更換為從庫。
三、RedisTemplate
- 配置檔案參考:
spring:
data:
redis:
# 這裡只需配置主節點的資訊即可
# RedisTemplate可以從主節點資訊中獲取從節點資訊
host: 192.168.88.130
port: 6379
password: root
jedis:
pool:
# 最大連線數
max-active: 10
# 最大空閒連線數
max-idle: 5
# 最小空閒
min-idle: 1
# 連線超時時間(毫秒)
max-wait: 8000
sentinel:
password: root
master: jobs
nodes:
- 192.168.88.130:26379
- 192.168.88.130:26479
- 192.168.88.130:26579
個人問題記錄:
-
在搭建sentinel時:
[root@centos redis-cluster]# docker-compose ps NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS redis0 redis "docker-entrypoint.s…" redis0 4 days ago Up 26 minutes redis1 redis "docker-entrypoint.s…" redis1 4 days ago Up 26 minutes redis2 redis "docker-entrypoint.s…" redis2 4 days ago Up 26 minutes redis3 redis "docker-entrypoint.s…" redis3 4 days ago Up 26 minutes redis4 redis "docker-entrypoint.s…" redis4 4 days ago Up 26 minutes sentinel1 redis "docker-entrypoint.s…" sentinel1 2 minutes ago Restarting (1) 20 seconds ago sentinel2 redis "docker-entrypoint.s…" sentinel2 2 minutes ago Up 2 minutes sentinel3 redis "docker-entrypoint.s…" sentinel3 2 minutes ago Up 2 minutes
- 檢視命令發現
sentinel1
容器在啟動後處於不斷重啟的狀態,這通常表示該容器內的 Redis 哨兵服務遇到了錯誤並退出 - 於是檢視日誌:
[root@centos redis-cluster]# docker-compose logs sentinel1 sentinel1 | sentinel1 | *** FATAL CONFIG FILE ERROR (Redis 7.4.0) *** sentinel1 | Reading the configuration file, at line 2 sentinel1 | >>> 'rt 26379' sentinel1 | Bad directive or wrong number of arguments
- 發現
sentinel1
的配置檔案在第 2 行存在語法問題。日誌中提到的內容>>> 'rt 26379'
,發現是配置檔案拼寫的錯誤,修改配置檔案即可。
- 檢視命令發現
[root@centos redis-cluster]# docker-compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
redis0 redis "docker-entrypoint.s…" redis0 4 days ago Up 41 minutes
redis1 redis "docker-entrypoint.s…" redis1 4 days ago Up 41 minutes
redis2 redis "docker-entrypoint.s…" redis2 4 days ago Up 41 minutes
redis3 redis "docker-entrypoint.s…" redis3 4 days ago Up 41 minutes
redis4 redis "docker-entrypoint.s…" redis4 4 days ago Up 41 minutes
sentinel1 redis "docker-entrypoint.s…" sentinel1 17 minutes ago Up 35 seconds
sentinel2 redis "docker-entrypoint.s…" sentinel2 17 minutes ago Up 17 minutes
sentinel3 redis "docker-entrypoint.s…" sentinel3 17 minutes ago Up 17 minutes
- 在模擬master節點當機時:
因為我一開始搭建的是“主從從”模式叢集,再在該基礎上搭建哨兵叢集,結構如下:
哨兵不直接支援級聯從節點的監控(即哨兵一般不會監控從節點的從節點 - 我們所搭建的redis3和redis4),但這時我們已經搭建好了,就不打算將redis3和redis4rm
,我們先將redis0 stop再start,然後發現:
當 Redis 哨兵檢測到主節點
redis0
不可用時,它將redis2
切換為新的主節點。由於redis3
和redis4
原本是redis2
的從節點,這個鏈條並未斷裂,且由於redis2
成為了主節點,哨兵將其下的所有從節點(包括原本的從節點的從節點)也作為它的從節點進行管理。
-
redis2
成為新的主節點後,redis1
、redis3
、和redis4
均會被識別為redis2
的直接從節點,形成多層次的直接複製。 -
因為哨兵在切換時沒有自動重設
redis3
和redis4
的主從關係,它們仍然保持與redis2
的連線。 -
我們在RDM中對redis進行
info replication
,觀察如下:
- 為什麼沒有
redis0
?redis0
作為redis2
的從節點重新連線時,可能還沒有完成所有的複製同步和狀態更新。即使redis0
成功連線為從節點,它的狀態可能還在初始化過程中,導致暫時沒有出現在redis2
的從節點列表中。當我們再次嘗試稍等片刻,然後再次使用info replication
檢查,就可以看到redis0
也成為了redis2
的slave
當我們對其中一個sentinel進行
sentinel slaves jobs
操作後,發現:
- 哨兵在切換後會將所有的下層節點(包括多級從節點)作為新的主節點的從節點進行管理。因此,當你在
sentinel slaves jobs
中查詢時,能看到所有屬於redis2
直接或間接從屬關係的節點(即redis1
、redis3
、redis4
等),都被列為它的從節點。
因此,為了減少不必要的麻煩,我們會簡化為一層“主-從”結構,以便哨兵更高效地管理複製關係。
參考博文:
Redis 哨兵叢集搭建並使用 RedisTemplate 實現讀寫分離
參考書籍:
《Redis核心技術與實戰》