搭建Redis哨兵叢集並使用RedisTemplate實現讀寫分離

尘尘尘發表於2024-10-10

一、理論相關

  • 透過上篇部落格:搭建Redis“主-從-從”模式叢集並使用 RedisTemplate 實現讀寫分離,我們已經搭建好了Redis“主-從-從”模式叢集並且實現讀寫分離,這裡會出現幾個問題:如果主庫當機了,我們就需要執行一個新主庫,比如說把一個從庫切換為主庫,把它當成主庫。這就會涉及到三個問題:

    1. 主庫真的掛了嗎?
    2. 該選擇哪個從庫作為主庫?
    3. 怎麼把新主庫的相關資訊通知給從庫和客戶端呢?
  • 由此,我們便引出哨兵機制

1、哨兵機制:主庫掛了,如何不間斷服務?

1.1、哨兵機制的基本流程

一個執行在特殊模式下的Redis程序,主從庫例項執行的同時,它也在執行。主要負責三個任務:

  1. 監控 - 需要判斷主庫是否處於下線狀態

    1. 哨兵程序在執行時,週期性地給所有的主從庫傳送PING命令,檢測它們是否仍線上執行
    2. 從庫沒有在規定時間內響應哨兵的PING命令(對PING命令響應超時),標記為“下線狀態”
    3. 主庫對PING命令響應超時,判定主庫下線,開始自動切換主庫的流程
  2. 選主(選擇主庫) - 決定哪個從庫例項作為主庫

    1. 主庫掛了以後,從很多個從庫裡,按照一定的規則選擇一個從庫例項,把它作為新的主庫
  3. 通知

    1. 把新主庫的連線資訊發給其它從庫,執行replicaof命令,和新主庫建立連線,並進行資料複製
    2. 把新主庫的連線資訊通知給客戶端,讓它們把請求操作發到新主庫

1.2、主觀下線和客觀下線

主庫:特別注意哨兵誤判的情況 - 主庫實際沒有下線,哨兵誤以為下線了

  • 一般發生在叢集網路壓力較大、網路擁塞,或主庫本身壓力較大的情況
  • 避免後續沒有價值的開銷

解決方法:

  • 多例項組成的叢集模式進行部署 - 哨兵叢集
  • 引入多個哨兵例項一起判斷,降低誤判率
  • 只有大多數哨兵例項都判斷主庫已經“主觀下線”,主庫才會被標記為“客觀下線”

image

  • 當有 N 個哨兵例項時,最好要有 N/2 + 1 個例項判斷主庫為“主觀下線”,才能最終判定主庫為“客觀下線”
  • 有多少個例項做出“主觀下線”的判斷才可以 - 可以由 Redis 管理員自行設定

1.3、如何選定新主庫?

  • 篩選 + 打分

    1. 在多個從庫中,先按照一定的篩選條件,把不符合條件的從庫去掉
    2. 再按照一定的規則,給剩下的從庫逐個打分,將得分最高的從庫選為新主庫

image-20241009165754869

  • 篩選條件

    1. 線上狀態
    2. 網路連線狀態
      • 配置項down-after-milliseconds * 10
      • down-after-milliseconds:認定主從庫斷連的最大連線超時時間
      • 如果在 down-after-milliseconds 毫秒內,主從節點都沒有透過網路聯絡上,就可以認為主從節點斷連了
      • 發生斷連的次數超過10次,這個從庫的網路狀況不好,不適合作為新主庫
  • 打分(在某一輪中,從庫得分最高,它就是主庫,選主過程結束;否則進行下一輪打分)

    1. 從庫優先順序(優先順序最高的從庫得分高)
    • 配置項slave-priority,給不同從庫設定不同優先順序
    • 比如:兩個從庫中記憶體大的例項設定高優先順序
    1. 從庫複製進度(和舊主庫同步程度最接近的從庫得分高)
    • 如果選擇和舊主庫同步最接近的那個從庫作為主庫,這個新主庫上就會有最新的資料
    • slave_repl_offset最接近master_repl_offset
    1. 從庫ID號(ID號小的從庫得分高)
    • 預設規定

1.4、小結

image

  • 組成哨兵機制可以解決主庫之間切換服務的問題,但同樣的,引入哨兵機制就相當於再引入例項,那麼我們又會面臨一些問題:

    1. 哨兵叢集中有例項掛了,怎麼辦,會影響主庫狀態判斷和選主嗎?
    2. 哨兵叢集多數例項達成共識,判斷出主庫“客觀下線”後,由哪個例項來執行主從切換呢?
  • 那麼接下來,我們就引出哨兵叢集的概念:

2、哨兵叢集:哨兵掛了,主從庫還能切換嗎?

  • 一旦多個例項組成了哨兵叢集,即使有哨兵例項出現故障掛掉了,其他哨兵還能繼續協作完成主從庫切換的工作,包括判定主庫是不是處於下線狀態,選擇新主庫,以及通知從庫和客戶端。

2.1、基於pub/sub機制的哨兵叢集組成

  • 同時,它也可以從主庫上訂閱訊息,獲得其他哨兵釋出的連線資訊
  • 除了哨兵例項,我們自己編寫的應用程式也可以透過 Redis 進行訊息的釋出和訂閱

頻道:訊息的類別

image

  • 哨兵除了彼此間建立連線形成叢集,還需要和從庫建立連線
  • 在哨兵的監控任務中,需要對主從庫都進行心跳判斷,而且在主從庫切換完成後,需要通知從庫,讓它們和新主庫同步

image

  • 主從庫切換後,客戶端也需要知道新主庫的連線資訊,才能向新主庫傳送請求操作
  • 哨兵還需要把新主庫的資訊告訴客戶端
  • 客戶端需要獲取到哨兵叢集在監控、選主、切換這個過程中發生的各種事件

2.2、基於pub/sub機制的客戶端事件通知

  • 從本質上說,哨兵就是一個執行在特定模式下的 Redis 例項,只不過它並不服務請求操作,只是完成監控、選主和通知的任務。
  • 每個哨兵例項也提供pub/sub機制

image

操作步驟:

  1. 客戶端讀取哨兵的配置檔案
  2. 獲得哨兵的地址和埠,和哨兵建立網路連線
  3. 在客戶端執行訂閱命令,獲取不同的事件訊息
SUBSCRIBE +odown
PSUBSRCIBE *
switch-master <master name> <oldip> <oldport> <newip> <newport>
  • 表示主庫已經切換,新主庫的IP地址和埠資訊已經有了
  • 客戶端不僅可以在主從切換後得到新主庫的連線資訊,還可以監控到主從庫切換過程中發生的各個重要事件
  • 客戶端就可以知道主從切換進行到哪一步,有助於瞭解切換進度

2.3、由哪個哨兵執行主從切換?

  • “投票仲裁”過程

image

在投票過程中,任何一個想成為 Leader 的哨兵,要滿足兩個條件:

  1. 拿到半數以上的贊成票
  2. 拿到的票數同時還需要大於等於哨兵配置檔案中的 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、小結

image

哨兵叢集的關鍵機制

  1. 基於 pub/sub 機制的哨兵叢集組成過程;
  2. 基於 INFO 命令的從庫列表,這可以幫助哨兵和從庫建立連線;
  3. 基於哨兵自身的 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為主庫,redis1redis2分別為從庫I、從庫II;redis3redis4分別為從庫II的從庫1和從庫2

  • 接下來,我們在該結構的基礎上,搭建sentinel哨兵叢集

  1. 首先,我們先看看上一次搭建叢集的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

  1. 新建目錄
[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
  1. 編輯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
  1. 然後,我們在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
  1. 最後,我們在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環境下檢視虛擬機器中搭建的哨兵狀態

  1. 進入到 Redis 目錄,在該目錄下開啟 cmd 命令列,執行 redis-cli.exe -h 192.168.88.130 -p 26379 -a root

image-20241009192901554

  1. 檢視master節點的資訊
sentinel master [sentinel叢集名稱]

image-20241009193355145

  1. 檢視除自己之外,sentinel 叢集中的其它 sentinel 節點資訊
sentinel sentinels [sentinel叢集名稱]

image-20241009195419792

image-20241009195457636

  1. 檢視slave節點的資訊
sentinel slaves [sentinel叢集名稱]

image-20241009193715097

image-20241009193811267

  • 注:哨兵不直接支援級聯從節點的監控(即哨兵一般不會監控從節點的從節點 - 我們所搭建的redis3和redis4),最佳實踐通常是避免級聯結構,使用簡單的“主從”模式,減少管理和故障切換的複雜性。
  • 因此,我們搭建的redis叢集如下:

image-20241009195201644

3、模擬master節點當機

  1. 我們將主庫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
  1. 我們再在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

個人問題記錄:

  1. 在搭建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 

  1. 在模擬master節點當機時:

因為我一開始搭建的是“主從從”模式叢集,再在該基礎上搭建哨兵叢集,結構如下:

image-20241010111723147

哨兵不直接支援級聯從節點的監控(即哨兵一般不會監控從節點的從節點 - 我們所搭建的redis3和redis4),但這時我們已經搭建好了,就不打算將redis3和redis4rm,我們先將redis0 stop再start,然後發現:

當 Redis 哨兵檢測到主節點 redis0 不可用時,它將 redis2 切換為新的主節點。由於 redis3redis4 原本是 redis2 的從節點,這個鏈條並未斷裂,且由於 redis2 成為了主節點,哨兵將其下的所有從節點(包括原本的從節點的從節點)也作為它的從節點進行管理

  • redis2 成為新的主節點後,redis1redis3、和 redis4 均會被識別為 redis2直接從節點,形成多層次的直接複製。

  • 因為哨兵在切換時沒有自動重設 redis3redis4 的主從關係,它們仍然保持與 redis2 的連線。

  • 我們在RDM中對redis進行info replication,觀察如下:

image-20241010112416474

  • 為什麼沒有redis0
    • redis0 作為 redis2 的從節點重新連線時,可能還沒有完成所有的複製同步和狀態更新。即使 redis0 成功連線為從節點,它的狀態可能還在初始化過程中,導致暫時沒有出現在 redis2 的從節點列表中。當我們再次嘗試稍等片刻,然後再次使用 info replication 檢查,就可以看到redis0也成為了redis2slave

當我們對其中一個sentinel進行sentinel slaves jobs操作後,發現:

image-20241009200231810

image-20241009200313041

image-20241009200352044

image-20241009200428858

  • 哨兵在切換後會將所有的下層節點(包括多級從節點)作為新的主節點的從節點進行管理。因此,當你在 sentinel slaves jobs 中查詢時,能看到所有屬於 redis2 直接或間接從屬關係的節點(即 redis1redis3redis4 等),都被列為它的從節點。

因此,為了減少不必要的麻煩,我們會簡化為一層“主-從”結構,以便哨兵更高效地管理複製關係。


參考博文:
Redis 哨兵叢集搭建並使用 RedisTemplate 實現讀寫分離

參考書籍:
《Redis核心技術與實戰》

相關文章