Redis-哨兵模式和高可用集群解析


 

 

前言

   Redis 的 主從復制 模式下,一旦 主節點 由於故障不能提供服務,需要手動將 從節點 晉升為 主節點,同時還要通知 客戶端 更新 主節點地址,這種故障處理方式從一定程度上是無法接受的。Redis 2.8 以后提供了 Redis Sentinel 哨兵機制 來解決這個問題。

正文

1. Redis高可用概述

在 Web 服務器中,高可用 是指服務器可以 正常訪問 的時間,衡量的標准是在 多長時間 內可以提供正常服務(99.9%99.99%99.999% 等等)。在 Redis 層面,高可用 的含義要寬泛一些,除了保證提供 正常服務(如 主從分離快速容災技術 等),還需要考慮 數據容量擴展數據安全 等等。

在 Redis 中,實現 高可用 的技術主要包括 持久化復制哨兵 和 集群,下面簡單說明它們的作用,以及解決了什么樣的問題:

  • 持久化:持久化是 最簡單的 高可用方法。它的主要作用是 數據備份,即將數據存儲在 硬盤,保證數據不會因進程退出而丟失。

  • 復制:復制是高可用 Redis 的基礎,哨兵 和 集群 都是在 復制基礎 上實現高可用的。復制主要實現了數據的多機備份以及對於讀操作的負載均衡和簡單的故障恢復。缺陷是故障恢復無法自動化、寫操作無法負載均衡、存儲能力受到單機的限制。

  • 哨兵:在復制的基礎上,哨兵實現了 自動化 的 故障恢復。缺陷是 寫操作 無法 負載均衡存儲能力 受到 單機 的限制。

  • 集群:通過集群,Redis 解決了 寫操作 無法 負載均衡 以及 存儲能力 受到 單機限制 的問題,實現了較為 完善 的 高可用方案

 

2. Redis Sentinel的基本概念

Redis Sentinel 是 Redis 高可用 的實現方案。Sentinel 是一個管理多個 Redis 實例的工具,它可以實現對 Redis 的 監控通知自動故障轉移。下面先對 Redis Sentinel 的 基本概念 進行簡單的介紹。

基本名詞說明:

基本名詞 邏輯結構 物理結構
Redis數據節點 主節點和從節點 主節點和從節點的進程
主節點(master) Redis主數據庫 一個獨立的Redis進程
從節點(slave) Redis從數據庫 一個獨立的Redis進程
Sentinel節點 監控Redis數據節點 一個獨立的Sentinel進程
Sentinel節點集合 若干Sentinel節點的抽象組合 若干Sentinel節點進程
Redis Sentinel Redis高可用實現方案 Sentinel節點集合和Redis數據節點進程
應用客戶端 泛指一個或多個客戶端 一個或者多個客戶端進程或者線程

如圖所示,Redis 的 主從復制模式 和 Sentinel 高可用架構 的示意圖:

3. Redis主從復制的問題

Redis 主從復制 可將 主節點 數據同步給 從節點,從節點此時有兩個作用:

  1. 一旦 主節點宕機從節點 作為 主節點 的 備份 可以隨時頂上來。
  2. 擴展 主節點 的 讀能力,分擔主節點讀壓力。

主從復制 同時存在以下幾個問題:

  1. 一旦 主節點宕機從節點 晉升成 主節點,同時需要修改 應用方 的 主節點地址,還需要命令所有 從節點去 復制 新的主節點,整個過程需要 人工干預

  2. 主節點 的 寫能力 受到 單機的限制

  3. 主節點 的 存儲能力 受到 單機的限制

  4. 原生復制 的弊端在早期的版本中也會比較突出,比如:Redis 復制中斷 后,從節點 會發起 psync。此時如果 同步不成功,則會進行 全量同步主庫 執行 全量備份 的同時,可能會造成毫秒或秒級的 卡頓

4. Redis Sentinel深入探究

4.1. Redis Sentinel的架構

 

4.2. Redis Sentinel的主要功能

Sentinel 的主要功能包括 主節點存活檢測主從運行情況檢測自動故障轉移 (failover)、主從切換Redis 的 Sentinel 最小配置是 一主一從

Redis 的 Sentinel 系統可以用來管理多個 Redis 服務器,該系統可以執行以下四個任務:

  • 監控

Sentinel 會不斷的檢查 主服務器 和 從服務器 是否正常運行。

  • 通知

當被監控的某個 Redis 服務器出現問題,Sentinel 通過 API 腳本 向 管理員 或者其他的 應用程序 發送通知。

  • 自動故障轉移

當 主節點 不能正常工作時,Sentinel 會開始一次 自動的 故障轉移操作,它會將與 失效主節點 是 主從關系的其中一個 從節點 升級為新的 主節點,並且將其他的 從節點 指向 新的主節點

  • 配置提供者

在 Redis Sentinel 模式下,客戶端應用 在初始化時連接的是 Sentinel 節點集合,從中獲取 主節點 的信息。

4.3. 主觀下線和客觀下線

默認情況下,每個 Sentinel 節點會以 每秒一次 的頻率對 Redis 節點和 其它 的 Sentinel 節點發送 PING命令,並通過節點的 回復 來判斷節點是否在線。

  • 主觀下線

主觀下線 適用於所有 主節點 和 從節點。如果在 down-after-milliseconds 毫秒內,Sentinel 沒有收到 目標節點 的有效回復,則會判定 該節點 為 主觀下線

  • 客觀下線

客觀下線 只適用於 主節點。如果 主節點 出現故障,Sentinel 節點會通過 sentinel is-master-down-by-addr 命令,向其它 Sentinel 節點詢問對該節點的 狀態判斷。如果超過 <quorum> 個數的節點判定 主節點 不可達,則該 Sentinel 節點會判斷 主節點 為 客觀下線

4.4. Sentinel的通信命令

Sentinel 節點連接一個 Redis 實例的時候,會創建 cmd 和 pub/sub 兩個 連接Sentinel 通過 cmd 連接給 Redis 發送命令,通過 pub/sub 連接到 Redis 實例上的其他 Sentinel 實例。

Sentinel 與 Redis 主節點 和 從節點 交互的命令,主要包括:

命令 作 用
PING Sentinel 向 Redis 節點發送 PING 命令,檢查節點的狀態
INFO Sentinel 向 Redis 節點發送 INFO 命令,獲取它的 從節點信息
PUBLISH Sentinel 向其監控的 Redis 節點 __sentinel__:hello 這個 channel 發布 自己的信息及 主節點 相關的配置
SUBSCRIBE Sentinel 通過訂閱 Redis 主節點 和 從節點 的 __sentinel__:hello 這個 channnel,獲取正在監控相同服務的其他 Sentinel 節點

Sentinel 與 Sentinel 交互的命令,主要包括:

命令 作 用
PING Sentinel 向其他 Sentinel 節點發送 PING 命令,檢查節點的狀態
SENTINEL:is-master-down-by-addr 和其他 Sentinel 協商 主節點 的狀態,如果 主節點 處於 SDOWN 狀態,則投票自動選出新的 主節點

4.5. Redis Sentinel的工作原理

每個 Sentinel 節點都需要 定期執行 以下任務:

  • 每個 Sentinel 以 每秒鍾 一次的頻率,向它所知的 主服務器從服務器 以及其他 Sentinel 實例 發送一個 PING 命令。

  1. 如果一個 實例instance)距離 最后一次 有效回復 PING 命令的時間超過 down-after-milliseconds 所指定的值,那么這個實例會被 Sentinel 標記為 主觀下線

  1. 如果一個 主服務器 被標記為 主觀下線,那么正在 監視 這個 主服務器 的所有 Sentinel 節點,要以 每秒一次 的頻率確認 主服務器 的確進入了 主觀下線 狀態。

  1. 如果一個 主服務器 被標記為 主觀下線,並且有 足夠數量 的 Sentinel(至少要達到 配置文件 指定的數量)在指定的 時間范圍 內同意這一判斷,那么這個 主服務器 被標記為 客觀下線

  1. 在一般情況下, 每個 Sentinel 會以每 10 秒一次的頻率,向它已知的所有 主服務器 和 從服務器 發送 INFO 命令。當一個 主服務器 被 Sentinel 標記為 客觀下線 時,Sentinel 向 下線主服務器 的所有 從服務器 發送 INFO 命令的頻率,會從 10 秒一次改為 每秒一次

  1. Sentinel 和其他 Sentinel 協商 主節點 的狀態,如果 主節點 處於 SDOWN 狀態,則投票自動選出新的 主節點。將剩余的 從節點 指向 新的主節點 進行 數據復制

  1. 當沒有足夠數量的 Sentinel 同意 主服務器 下線時, 主服務器 的 客觀下線狀態 就會被移除。當 主服務器 重新向 Sentinel 的 PING 命令返回 有效回復 時,主服務器 的 主觀下線狀態 就會被移除。

        注意:一個有效的 PING 回復可以是:+PONG-LOADING 或者 -MASTERDOWN。如果 服務器返回除以上三種回復之外的其他回復,又或者在 指定時間 內沒有回復 PING 命令, 那么 Sentinel 認為服務器返回的回復 無效non-valid)。

 

5. Redis Sentinel搭建

5.1. Redis Sentinel的部署須知

  1. 一個穩健的 Redis Sentinel 集群,應該使用至少 三個Sentinel 實例,並且保證講這些實例放到 不同的機器 上,甚至不同的 物理區域

  2. Sentinel 無法保證 強一致性

  3. 常見的 客戶端應用庫 都支持 Sentinel

  4. Sentinel 需要通過不斷的 測試 和 觀察,才能保證高可用。

5.2. Redis Sentinel的配置文件

# 哨兵sentinel實例運行的端口,默認26379  
port 26379
# 哨兵sentinel的工作目錄
dir ./

# 哨兵sentinel監控的redis主節點的 
## ip:主機ip地址
## port:哨兵端口號
## master-name:可以自己命名的主節點名字(只能由字母A-z、數字0-9 、這三個字符".-_"組成。)
## quorum:當這些quorum個數sentinel哨兵認為master主節點失聯 那么這時 客觀上認為主節點失聯了  
# sentinel monitor <master-name> <ip> <redis-port> <quorum>  
sentinel monitor mymaster 127.0.0.1 6379 2

# 當在Redis實例中開啟了requirepass <foobared>,所有連接Redis實例的客戶端都要提供密碼。
# sentinel auth-pass <master-name> <password>  
sentinel auth-pass mymaster 123456  

# 指定主節點應答哨兵sentinel的最大時間間隔,超過這個時間,哨兵主觀上認為主節點下線,默認30秒  
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000  

# 指定了在發生failover主備切換時,最多可以有多少個slave同時對新的master進行同步。這個數字越小,完成failover所需的時間就越長;反之,但是如果這個數字越大,就意味着越多的slave因為replication而不可用。可以通過將這個值設為1,來保證每次只有一個slave,處於不能處理命令請求的狀態。
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1  

# 故障轉移的超時時間failover-timeout,默認三分鍾,可以用在以下這些方面:
## 1. 同一個sentinel對同一個master兩次failover之間的間隔時間。  
## 2. 當一個slave從一個錯誤的master那里同步數據時開始,直到slave被糾正為從正確的master那里同步數據時結束。  
## 3. 當想要取消一個正在進行的failover時所需要的時間。
## 4.當進行failover時,配置所有slaves指向新的master所需的最大時間。不過,即使過了這個超時,slaves依然會被正確配置為指向master,但是就不按parallel-syncs所配置的規則來同步數據了
# sentinel failover-timeout <master-name> <milliseconds>  
sentinel failover-timeout mymaster 180000

# 當sentinel有任何警告級別的事件發生時(比如說redis實例的主觀失效和客觀失效等等),將會去調用這個腳本。一個腳本的最大執行時間為60s,如果超過這個時間,腳本將會被一個SIGKILL信號終止,之后重新執行。
# 對於腳本的運行結果有以下規則:  
## 1. 若腳本執行后返回1,那么該腳本稍后將會被再次執行,重復次數目前默認為10。
## 2. 若腳本執行后返回2,或者比2更高的一個返回值,腳本將不會重復執行。  
## 3. 如果腳本在執行過程中由於收到系統中斷信號被終止了,則同返回值為1時的行為相同。
# sentinel notification-script <master-name> <script-path>  
sentinel notification-script mymaster /var/redis/notify.sh

# 這個腳本應該是通用的,能被多次調用,不是針對性的。
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

5.3. Redis Sentinel的節點規划

角色 IP地址 端口號
Redis Master 10.206.20.231 16379
Redis Slave1 10.206.20.231 26379
Redis Slave2 10.206.20.231 36379
Redis Sentinel1 10.206.20.231 16380
Redis Sentinel2 10.206.20.231 26380
Redis Sentinel3 10.206.20.231 36380

5.4. Redis Sentinel的配置搭建

5.4.1. Redis-Server的配置管理

分別拷貝三份 redis.conf 文件到 /usr/local/redis-sentinel 目錄下面。三個配置文件分別對應 masterslave1 和 slave2 三個 Redis 節點的 啟動配置

$ sudo cp /usr/local/redis-4.0.11/redis.conf /usr/local/redis-sentinel/redis-16379.conf
$ sudo cp /usr/local/redis-4.0.11/redis.conf /usr/local/redis-sentinel/redis-26379.conf
$ sudo cp /usr/local/redis-4.0.11/redis.conf /usr/local/redis-sentinel/redis-36379.conf

分別修改三份配置文件如下:

  • 主節點:redis-16379.conf
daemonize yes
pidfile /var/run/redis-16379.pid
logfile /var/log/redis/redis-16379.log
port 16379
bind 0.0.0.0
timeout 300
databases 16
dbfilename dump-16379.db
dir ./redis-workdir
masterauth 123456
requirepass 123456
  • 從節點1:redis-26379.conf
daemonize yes
pidfile /var/run/redis-26379.pid
logfile /var/log/redis/redis-26379.log
port 26379
bind 0.0.0.0
timeout 300
databases 16
dbfilename dump-26379.db
dir ./redis-workdir
masterauth 123456
requirepass 123456
slaveof 127.0.0.1 16379
  • 從節點2:redis-36379.conf
daemonize yes
pidfile /var/run/redis-36379.pid
logfile /var/log/redis/redis-36379.log
port 36379
bind 0.0.0.0
timeout 300
databases 16
dbfilename dump-36379.db
dir ./redis-workdir
masterauth 123456
requirepass 123456
slaveof 127.0.0.1 16379

 如果要做 自動故障轉移,建議所有的 redis.conf 都設置 masterauth。因為 自動故障 只會重寫 主從關系,即 slaveof,不會自動寫入 masterauth。如果 Redis 原本沒有設置密碼,則可以忽略。

5.4.2. Redis-Server啟動驗證

按順序分別啟動 1637926379 和 36379 三個 Redis 節點,啟動命令和啟動日志如下:

Redis 的啟動命令:

$ sudo redis-server /usr/local/redis-sentinel/redis-16379.conf
$ sudo redis-server /usr/local/redis-sentinel/redis-26379.conf
$ sudo redis-server /usr/local/redis-sentinel/redis-36379.conf

查看 Redis 的啟動進程:

$ ps -ef | grep redis-server
    0  7127     1   0  2:16下午 ??         0:01.84 redis-server 0.0.0.0:16379 
    0  7133     1   0  2:16下午 ??         0:01.73 redis-server 0.0.0.0:26379 
    0  7137     1   0  2:16下午 ??         0:01.70 redis-server 0.0.0.0:36379 

查看 Redis 的啟動日志:

  • 節點 redis-16379
$ cat /var/log/redis/redis-16379.log 
7126:C 22 Aug 14:16:38.907 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7126:C 22 Aug 14:16:38.908 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7126, just started
7126:C 22 Aug 14:16:38.908 # Configuration loaded
7127:M 22 Aug 14:16:38.910 * Increased maximum number of open files to 10032 (it was originally set to 256).
7127:M 22 Aug 14:16:38.912 * Running mode=standalone, port=16379.
7127:M 22 Aug 14:16:38.913 # Server initialized
7127:M 22 Aug 14:16:38.913 * Ready to accept connections
7127:M 22 Aug 14:16:48.416 * Slave 127.0.0.1:26379 asks for synchronization
7127:M 22 Aug 14:16:48.416 * Full resync requested by slave 127.0.0.1:26379
7127:M 22 Aug 14:16:48.416 * Starting BGSAVE for SYNC with target: disk
7127:M 22 Aug 14:16:48.416 * Background saving started by pid 7134
7134:C 22 Aug 14:16:48.433 * DB saved on disk
7127:M 22 Aug 14:16:48.487 * Background saving terminated with success
7127:M 22 Aug 14:16:48.494 * Synchronization with slave 127.0.0.1:26379 succeeded
7127:M 22 Aug 14:16:51.848 * Slave 127.0.0.1:36379 asks for synchronization
7127:M 22 Aug 14:16:51.849 * Full resync requested by slave 127.0.0.1:36379
7127:M 22 Aug 14:16:51.849 * Starting BGSAVE for SYNC with target: disk
7127:M 22 Aug 14:16:51.850 * Background saving started by pid 7138
7138:C 22 Aug 14:16:51.862 * DB saved on disk
7127:M 22 Aug 14:16:51.919 * Background saving terminated with success
7127:M 22 Aug 14:16:51.923 * Synchronization with slave 127.0.0.1:36379 succeeded

以下兩行日志日志表明,redis-16379 作為 Redis 的 主節點redis-26379 和 redis-36379 作為 從節點,從 主節點 同步數據。

7127:M 22 Aug 14:16:48.416 * Slave 127.0.0.1:26379 asks for synchronization
7127:M 22 Aug 14:16:51.848 * Slave 127.0.0.1:36379 asks for synchronization
  • 節點 redis-26379
$ cat /var/log/redis/redis-26379.log 
7132:C 22 Aug 14:16:48.407 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7132:C 22 Aug 14:16:48.408 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7132, just started
7132:C 22 Aug 14:16:48.408 # Configuration loaded
7133:S 22 Aug 14:16:48.410 * Increased maximum number of open files to 10032 (it was originally set to 256).
7133:S 22 Aug 14:16:48.412 * Running mode=standalone, port=26379.
7133:S 22 Aug 14:16:48.413 # Server initialized
7133:S 22 Aug 14:16:48.413 * Ready to accept connections
7133:S 22 Aug 14:16:48.413 * Connecting to MASTER 127.0.0.1:16379
7133:S 22 Aug 14:16:48.413 * MASTER <-> SLAVE sync started
7133:S 22 Aug 14:16:48.414 * Non blocking connect for SYNC fired the event.
7133:S 22 Aug 14:16:48.414 * Master replied to PING, replication can continue...
7133:S 22 Aug 14:16:48.415 * Partial resynchronization not possible (no cached master)
7133:S 22 Aug 14:16:48.417 * Full resync from master: 211d3b4eceaa3af4fe5c77d22adf06e1218e0e7b:0
7133:S 22 Aug 14:16:48.494 * MASTER <-> SLAVE sync: receiving 176 bytes from master
7133:S 22 Aug 14:16:48.495 * MASTER <-> SLAVE sync: Flushing old data
7133:S 22 Aug 14:16:48.496 * MASTER <-> SLAVE sync: Loading DB in memory
7133:S 22 Aug 14:16:48.498 * MASTER <-> SLAVE sync: Finished with success
  • 節點 redis-36379
$ cat /var/log/redis/redis-36379.log 
7136:C 22 Aug 14:16:51.839 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7136:C 22 Aug 14:16:51.840 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7136, just started
7136:C 22 Aug 14:16:51.841 # Configuration loaded
7137:S 22 Aug 14:16:51.843 * Increased maximum number of open files to 10032 (it was originally set to 256).
7137:S 22 Aug 14:16:51.845 * Running mode=standalone, port=36379.
7137:S 22 Aug 14:16:51.845 # Server initialized
7137:S 22 Aug 14:16:51.846 * Ready to accept connections
7137:S 22 Aug 14:16:51.846 * Connecting to MASTER 127.0.0.1:16379
7137:S 22 Aug 14:16:51.847 * MASTER <-> SLAVE sync started
7137:S 22 Aug 14:16:51.847 * Non blocking connect for SYNC fired the event.
7137:S 22 Aug 14:16:51.847 * Master replied to PING, replication can continue...
7137:S 22 Aug 14:16:51.848 * Partial resynchronization not possible (no cached master)
7137:S 22 Aug 14:16:51.850 * Full resync from master: 211d3b4eceaa3af4fe5c77d22adf06e1218e0e7b:14
7137:S 22 Aug 14:16:51.923 * MASTER <-> SLAVE sync: receiving 176 bytes from master
7137:S 22 Aug 14:16:51.923 * MASTER <-> SLAVE sync: Flushing old data
7137:S 22 Aug 14:16:51.924 * MASTER <-> SLAVE sync: Loading DB in memory
7137:S 22 Aug 14:16:51.927 * MASTER <-> SLAVE sync: Finished with success

5.4.3. Sentinel的配置管理

分別拷貝三份 redis-sentinel.conf 文件到 /usr/local/redis-sentinel 目錄下面。三個配置文件分別對應 masterslave1 和 slave2 三個 Redis 節點的 哨兵配置

$ sudo cp /usr/local/redis-4.0.11/sentinel.conf /usr/local/redis-sentinel/sentinel-16380.conf
$ sudo cp /usr/local/redis-4.0.11/sentinel.conf /usr/local/redis-sentinel/sentinel-26380.conf
$ sudo cp /usr/local/redis-4.0.11/sentinel.conf /usr/local/redis-sentinel/sentinel-36380.conf
  • 節點1:sentinel-16380.conf
protected-mode no
bind 0.0.0.0
port 16380
daemonize yes
sentinel monitor master 127.0.0.1 16379 2
sentinel down-after-milliseconds master 5000
sentinel failover-timeout master 180000
sentinel parallel-syncs master 1
sentinel auth-pass master 123456
logfile /var/log/redis/sentinel-16380.log
  • 節點2:sentinel-26380.conf
protected-mode no
bind 0.0.0.0
port 26380
daemonize yes
sentinel monitor master 127.0.0.1 16379 2
sentinel down-after-milliseconds master 5000
sentinel failover-timeout master 180000
sentinel parallel-syncs master 1
sentinel auth-pass master 123456
logfile /var/log/redis/sentinel-26380.log
  • 節點3:sentinel-36380.conf
protected-mode no
bind 0.0.0.0
port 36380
daemonize yes
sentinel monitor master 127.0.0.1 16379 2
sentinel down-after-milliseconds master 5000
sentinel failover-timeout master 180000
sentinel parallel-syncs master 1
sentinel auth-pass master 123456
logfile /var/log/redis/sentinel-36380.log

5.4.4. Sentinel啟動驗證

按順序分別啟動 1638026380 和 36380 三個 Sentinel 節點,啟動命令和啟動日志如下:

$ sudo redis-sentinel /usr/local/redis-sentinel/sentinel-16380.conf
$ sudo redis-sentinel /usr/local/redis-sentinel/sentinel-26380.conf
$ sudo redis-sentinel /usr/local/redis-sentinel/sentinel-36380.conf

查看 Sentinel 的啟動進程:

$ ps -ef | grep redis-sentinel
    0  7954     1   0  3:30下午 ??         0:00.05 redis-sentinel 0.0.0.0:16380 [sentinel] 
    0  7957     1   0  3:30下午 ??         0:00.05 redis-sentinel 0.0.0.0:26380 [sentinel] 
    0  7960     1   0  3:30下午 ??         0:00.04 redis-sentinel 0.0.0.0:36380 [sentinel] 

查看 Sentinel 的啟動日志:

  • 節點 sentinel-16380
$ cat /var/log/redis/sentinel-16380.log 
7953:X 22 Aug 15:30:27.245 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7953:X 22 Aug 15:30:27.245 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7953, just started
7953:X 22 Aug 15:30:27.245 # Configuration loaded
7954:X 22 Aug 15:30:27.247 * Increased maximum number of open files to 10032 (it was originally set to 256).
7954:X 22 Aug 15:30:27.249 * Running mode=sentinel, port=16380.
7954:X 22 Aug 15:30:27.250 # Sentinel ID is 69d05b86a82102a8919231fd3c2d1f21ce86e000
7954:X 22 Aug 15:30:27.250 # +monitor master master 127.0.0.1 16379 quorum 2
7954:X 22 Aug 15:30:32.286 # +sdown sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 16379
7954:X 22 Aug 15:30:34.588 # -sdown sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 16379

sentinel-16380 節點的 Sentinel ID 為 69d05b86a82102a8919231fd3c2d1f21ce86e000,並通過 Sentinel ID 把自身加入 sentinel 集群中。

  • 節點 sentinel-26380
$ cat /var/log/redis/sentinel-26380.log 
7956:X 22 Aug 15:30:30.900 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7956:X 22 Aug 15:30:30.901 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7956, just started
7956:X 22 Aug 15:30:30.901 # Configuration loaded
7957:X 22 Aug 15:30:30.904 * Increased maximum number of open files to 10032 (it was originally set to 256).
7957:X 22 Aug 15:30:30.905 * Running mode=sentinel, port=26380.
7957:X 22 Aug 15:30:30.906 # Sentinel ID is 21e30244cda6a3d3f55200bcd904d0877574e506
7957:X 22 Aug 15:30:30.906 # +monitor master master 127.0.0.1 16379 quorum 2
7957:X 22 Aug 15:30:30.907 * +slave slave 127.0.0.1:26379 127.0.0.1 26379 @ master 127.0.0.1 16379
7957:X 22 Aug 15:30:30.911 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 16379
7957:X 22 Aug 15:30:36.311 * +sentinel sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 16379

sentinel-26380 節點的 Sentinel ID 為 21e30244cda6a3d3f55200bcd904d0877574e506,並通過 Sentinel ID 把自身加入 sentinel 集群中。此時 sentinel 集群中已有 sentinel-16380 和 sentinel-26380 兩個節點。

  • 節點 sentinel-36380
$ cat /var/log/redis/sentinel-36380.log 
7959:X 22 Aug 15:30:34.273 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7959:X 22 Aug 15:30:34.274 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=7959, just started
7959:X 22 Aug 15:30:34.274 # Configuration loaded
7960:X 22 Aug 15:30:34.276 * Increased maximum number of open files to 10032 (it was originally set to 256).
7960:X 22 Aug 15:30:34.277 * Running mode=sentinel, port=36380.
7960:X 22 Aug 15:30:34.278 # Sentinel ID is fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7
7960:X 22 Aug 15:30:34.278 # +monitor master master 127.0.0.1 16379 quorum 2
7960:X 22 Aug 15:30:34.279 * +slave slave 127.0.0.1:26379 127.0.0.1 26379 @ master 127.0.0.1 16379
7960:X 22 Aug 15:30:34.283 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 16379
7960:X 22 Aug 15:30:34.993 * +sentinel sentinel 21e30244cda6a3d3f55200bcd904d0877574e506 127.0.0.1 26380 @ master 127.0.0.1 16379

sentinel-36380 節點的 Sentinel ID 為 fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7,並通過 Sentinel ID 把自身加入 sentinel 集群中。此時 sentinel 集群中已有 sentinel-16380sentinel-26380 和 sentinel-36380 三個節點。

5.4.5. Sentinel配置刷新

  • 節點1:sentinel-16380.conf

sentinel-16380.conf 文件新生成如下的配置項:

# Generated by CONFIG REWRITE
dir "/usr/local/redis-sentinel"
sentinel config-epoch master 0
sentinel leader-epoch master 0
sentinel known-slave master 127.0.0.1 36379
sentinel known-slave master 127.0.0.1 26379
sentinel known-sentinel master 127.0.0.1 26380 21e30244cda6a3d3f55200bcd904d0877574e506
sentinel known-sentinel master 127.0.0.1 36380 fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7
sentinel current-epoch 0

可以注意到,sentinel-16380.conf 刷新寫入了 Redis 主節點關聯的所有 從節點 redis-26379 和 redis-36379,同時寫入了其余兩個 Sentinel 節點 sentinel-26380 和 sentinel-36380 的 IP 地址,端口號 和 Sentinel ID

# Generated by CONFIG REWRITE
dir "/usr/local/redis-sentinel"
sentinel config-epoch master 0
sentinel leader-epoch master 0
sentinel known-slave master 127.0.0.1 26379
sentinel known-slave master 127.0.0.1 36379
sentinel known-sentinel master 127.0.0.1 36380 fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7
sentinel known-sentinel master 127.0.0.1 16380 69d05b86a82102a8919231fd3c2d1f21ce86e000
sentinel current-epoch 0

可以注意到,sentinel-26380.conf 刷新寫入了 Redis 主節點關聯的所有 從節點 redis-26379 和 redis-36379,同時寫入了其余兩個 Sentinel 節點 sentinel-36380 和 sentinel-16380 的 IP 地址,端口號 和 Sentinel ID

# Generated by CONFIG REWRITE
dir "/usr/local/redis-sentinel"
sentinel config-epoch master 0
sentinel leader-epoch master 0
sentinel known-slave master 127.0.0.1 36379
sentinel known-slave master 127.0.0.1 26379
sentinel known-sentinel master 127.0.0.1 16380 69d05b86a82102a8919231fd3c2d1f21ce86e000
sentinel known-sentinel master 127.0.0.1 26380 21e30244cda6a3d3f55200bcd904d0877574e506
sentinel current-epoch 0

可以注意到,sentinel-36380.conf 刷新寫入了 Redis 主節點關聯的所有 從節點 redis-26379 和 redis-36379,同時寫入了其余兩個 Sentinel 節點 sentinel-16380 和 sentinel-26380 的 IP 地址,端口號 和 Sentinel ID

5.5. Sentinel時客戶端命令

> PING sentinel                  #檢查其他 Sentinel 節點的狀態,返回 PONG 為正常。
> SENTINEL masters               #顯示被監控的所有 主節點 以及它們的狀態。
> SENTINEL master <master_name>  #顯示指定 主節點 的信息和狀態。
> SENTINEL slaves <master_name>  #顯示指定 主節點 的所有 從節點 以及它們的狀態。
> SENTINEL get-master-addr-by-name <master_name> #返回指定 主節點 的 IP 地址和 端口。如果正在進行 failover 或者 failover 已經完成,將會顯示被提升為 主節點 的 從節點 的 IP 地址和 端口
> SENTINEL reset <pattern>       #重置名字匹配該 正則表達式 的所有的 主節點 的狀態信息,清除它之前的 狀態信息,以及 從節點 的信息。
>SENTINEL failover <master_name> #強制當前 Sentinel 節點執行 failover,並且不需要得到其他 Sentinel 節點的同意。但是 failover后會將 最新的配置 發送給其他 Sentinel 節點。 

6. Redis Sentinel故障切換與恢復

6.1. Redis CLI客戶端跟蹤

$ kill -9 7127        #上面的日志顯示,redis-16379 節點為 主節點,它的進程 ID 為 7127。為了模擬 Redis 主節點故障,強制殺掉這個進程。
$ redis-cli -p 16380  #使用 redis-cli 客戶端命令進入 sentinel-16380 節點,查看 Redis 節點 的狀態信息。
  • 查看 Redis 主從集群的 主節點 信息。可以發現 redis-26379 晉升為 新的主節點
127.0.0.1:16380> SENTINEL master master
 1) "name"
 2) "master"
 3) "ip"
 4) "127.0.0.1"
 5) "port"
 6) "26379"
 7) "runid"
 8) "b8ca3b468a95d1be5efe1f50c50636cafe48c59f"
 9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "588"
19) "last-ping-reply"
20) "588"
21) "down-after-milliseconds"
22) "5000"
23) "info-refresh"
24) "9913"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "663171"
29) "config-epoch"
30) "1"
31) "num-slaves"
32) "2"
33) "num-other-sentinels"
34) "2"
35) "quorum"
36) "2"
37) "failover-timeout"
38) "180000"
39) "parallel-syncs"
40) "1"

6.2. Redis Sentinel日志跟蹤

查看任意 Sentinel 節點的日志如下:

7954:X 22 Aug 18:40:22.504 # +tilt #tilt mode entered
7954:X 22 Aug 18:40:32.197 # +tilt #tilt mode entered
7954:X 22 Aug 18:41:02.241 # -tilt #tilt mode exited
7954:X 22 Aug 18:48:24.550 # +sdown master master 127.0.0.1 16379
7954:X 22 Aug 18:48:24.647 # +new-epoch 1
7954:X 22 Aug 18:48:24.651 # +vote-for-leader fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 1
7954:X 22 Aug 18:48:25.678 # +odown master master 127.0.0.1 16379 #quorum 3/2
7954:X 22 Aug 18:48:25.678 # Next failover delay: I will not start a failover before Wed Aug 22 18:54:24 2018
7954:X 22 Aug 18:48:25.709 # +config-update-from sentinel fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 127.0.0.1 36380 @ master 127.0.0.1 16379
7954:X 22 Aug 18:48:25.710 # +switch-master master 127.0.0.1 16379 127.0.0.1 26379
7954:X 22 Aug 18:48:25.710 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 26379
7954:X 22 Aug 18:48:25.711 * +slave slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 26379
7954:X 22 Aug 18:48:30.738 # +sdown slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 26379
7954:X 22 Aug 19:38:23.479 # -sdown slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 26379
  • 分析日志,可以發現 redis-16329 節點先進入 sdown主觀下線 狀態。
+sdown master master 127.0.0.1 16379
  • 哨兵檢測到 redis-16329 出現故障,Sentinel 進入一個 新紀元,從 0 變為 1
+new-epoch 1
  • 三個 Sentinel 節點開始協商 主節點 的狀態,判斷其是否需要 客觀下線
+vote-for-leader fd166dc66425dc1d9e2670e1f17cb94fe05f5fc7 1
  • 超過 quorum 個數的 Sentinel 節點認為 主節點 出現故障,redis-16329 節點進入 客觀下線 狀態。
+odown master master 127.0.0.1 16379 #quorum 3/2
  • Sentinal 進行 自動故障切換,協商選定 redis-26329 節點作為新的 主節點
+switch-master master 127.0.0.1 16379 127.0.0.1 26379
  • redis-36329 節點和已經 客觀下線 的 redis-16329 節點成為 redis-26479 的 從節點
7954:X 22 Aug 18:48:25.710 * +slave slave 127.0.0.1:36379 127.0.0.1 36379 @ master 127.0.0.1 26379
7954:X 22 Aug 18:48:25.711 * +slave slave 127.0.0.1:16379 127.0.0.1 16379 @ master 127.0.0.1 26379

6.3. Redis的配置文件

分別查看三個 redis 節點的配置文件,發生 主從切換 時 redis.conf 的配置會自動發生刷新。

  • 節點 redis-16379
daemonize yes
pidfile "/var/run/redis-16379.pid"
logfile "/var/log/redis/redis-16379.log"
port 16379
bind 0.0.0.0
timeout 300
databases 16
dbfilename "dump-16379.db"
dir "/usr/local/redis-sentinel/redis-workdir"
masterauth "123456"
requirepass "123456"
  • 節點 redis-26379
daemonize yes
pidfile "/var/run/redis-26379.pid"
logfile "/var/log/redis/redis-26379.log"
port 26379
bind 0.0.0.0
timeout 300
databases 16
dbfilename "dump-26379.db"
dir "/usr/local/redis-sentinel/redis-workdir"
masterauth "123456"
requirepass "123456"
  • 節點 redis-36379
daemonize yes
pidfile "/var/run/redis-36379.pid"
logfile "/var/log/redis/redis-36379.log"
port 36379
bind 0.0.0.0
timeout 300
databases 16
dbfilename "dump-36379.db"
dir "/usr/local/redis-sentinel/redis-workdir"
masterauth "123456"
requirepass "123456"
slaveof 127.0.0.1 26379

分析redis-26379 節點 slaveof 配置被移除,晉升為 主節點redis-16379 節點處於 宕機狀態redis-36379 的 slaveof 配置更新為 127.0.0.1 redis-26379,成為 redis-26379 的 從節點

重啟節點 redis-16379。待正常啟動后,再次查看它的 redis.conf 文件,配置如下:

daemonize yes
pidfile "/var/run/redis-16379.pid"
logfile "/var/log/redis/redis-16379.log"
port 16379
bind 0.0.0.0
timeout 300
databases 16
dbfilename "dump-16379.db"
dir "/usr/local/redis-sentinel/redis-workdir"
masterauth "123456"
requirepass "123456"
# Generated by CONFIG REWRITE
slaveof 127.0.0.1 26379

節點 redis-16379 的配置文件新增一行 slaveof 配置屬性,指向 redis-26379,即成為 新的主節點 的 從節點

小結

本文首先對 Redis 實現高可用的幾種模式做出了闡述,指出了 Redis 主從復制 的不足之處,進一步引入了 Redis Sentinel 哨兵模式 的相關概念,深入說明了 Redis Sentinel 的 具體功能基本原理高可用搭建和 自動故障切換 驗證等。

當然,Redis Sentinel 僅僅解決了 高可用 的問題,對於 主節點 單點寫入和單節點無法擴容等問題,還需要引入 Redis Cluster 集群模式 予以解決。

 


免責聲明!

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



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