前言
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
主從複製 可將 主節點 資料同步給 從節點,從節點此時有兩個作用:
- 一旦 主節點當機,從節點 作為 主節點 的 備份 可以隨時頂上來。
- 擴充套件 主節點 的 讀能力,分擔主節點讀壓力。
主從複製 同時存在以下幾個問題:
-
一旦 主節點當機,從節點 晉升成 主節點,同時需要修改 應用方 的 主節點地址,還需要命令所有 從節點 去 複製 新的主節點,整個過程需要 人工干預。
-
主節點 的 寫能力 受到 單機的限制。
-
主節點 的 儲存能力 受到 單機的限制。
-
原生複製 的弊端在早期的版本中也會比較突出,比如:
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
命令。
- 如果一個 例項(
instance
)距離 最後一次 有效回覆PING
命令的時間超過down-after-milliseconds
所指定的值,那麼這個例項會被Sentinel
標記為 主觀下線。
- 如果一個 主伺服器 被標記為 主觀下線,那麼正在 監視 這個 主伺服器 的所有
Sentinel
節點,要以 每秒一次 的頻率確認 主伺服器 的確進入了 主觀下線 狀態。
- 如果一個 主伺服器 被標記為 主觀下線,並且有 足夠數量 的
Sentinel
(至少要達到 配置檔案 指定的數量)在指定的 時間範圍 內同意這一判斷,那麼這個 主伺服器 被標記為 客觀下線。
- 在一般情況下, 每個
Sentinel
會以每10
秒一次的頻率,向它已知的所有 主伺服器 和 從伺服器 傳送INFO
命令。當一個 主伺服器 被Sentinel
標記為 客觀下線 時,Sentinel
向 下線主伺服器 的所有 從伺服器 傳送INFO
命令的頻率,會從10
秒一次改為 每秒一次。
Sentinel
和其他Sentinel
協商 主節點 的狀態,如果 主節點 處於SDOWN
狀態,則投票自動選出新的 主節點。將剩餘的 從節點 指向 新的主節點 進行 資料複製。
- 當沒有足夠數量的
Sentinel
同意 主伺服器 下線時, 主伺服器 的 客觀下線狀態 就會被移除。當 主伺服器 重新向Sentinel
的PING
命令返回 有效回覆 時,主伺服器 的 主觀下線狀態 就會被移除。
注意:一個有效的
PING
回覆可以是:+PONG
、-LOADING
或者-MASTERDOWN
。如果 伺服器 返回除以上三種回覆之外的其他回覆,又或者在 指定時間 內沒有回覆PING
命令, 那麼Sentinel
認為伺服器返回的回覆 無效(non-valid
)。
5. Redis Sentinel搭建
5.1. Redis Sentinel的部署須知
-
一個穩健的
Redis Sentinel
叢集,應該使用至少 三個Sentinel
例項,並且保證講這些例項放到 不同的機器 上,甚至不同的 物理區域。 -
Sentinel
無法保證 強一致性。 -
常見的 客戶端應用庫 都支援
Sentinel
。 -
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
目錄下面。三個配置檔案分別對應 master
、slave1
和 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啟動驗證
按順序分別啟動 16379
,26379
和 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
目錄下面。三個配置檔案分別對應 master
、slave1
和 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啟動驗證
按順序分別啟動 16380
,26380
和 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-16380
,sentinel-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時客戶端命令
- 檢查其他
Sentinel
節點的狀態,返回PONG
為正常。
> PING sentinel
複製程式碼
- 顯示被監控的所有 主節點 以及它們的狀態。
> SENTINEL masters
複製程式碼
- 顯示指定 主節點 的資訊和狀態。
> SENTINEL master <master_name>
複製程式碼
- 顯示指定 主節點 的所有 從節點 以及它們的狀態。
> SENTINEL slaves <master_name>
複製程式碼
返回指定 主節點 的 IP
地址和 埠。如果正在進行 failover
或者 failover
已經完成,將會顯示被提升為 主節點 的 從節點 的 IP
地址和 埠。
> SENTINEL get-master-addr-by-name <master_name>
複製程式碼
- 重置名字匹配該 正規表示式 的所有的 主節點 的狀態資訊,清除它之前的 狀態資訊,以及 從節點 的資訊。
> SENTINEL reset <pattern>
複製程式碼
- 強制當前
Sentinel
節點執行failover
,並且不需要得到其他Sentinel
節點的同意。但是failover
後會將 最新的配置 傳送給其他Sentinel
節點。
SENTINEL failover <master_name>
複製程式碼
6. Redis Sentinel故障切換與恢復
6.1. Redis CLI客戶端跟蹤
上面的日誌顯示,redis-16379
節點為 主節點,它的程式 ID
為 7127
。為了模擬 Redis
主節點故障,強制殺掉這個程式。
$ kill -9 7127
複製程式碼
使用 redis-cli
客戶端命令進入 sentinel-16380
節點,檢視 Redis
節點 的狀態資訊。
$ redis-cli -p 16380
複製程式碼
- 檢視
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
叢集模式 予以解決。
參考
《Redis 開發與運維》
歡迎關注技術公眾號: 零壹技術棧
本帳號將持續分享後端技術乾貨,包括虛擬機器基礎,多執行緒程式設計,高效能框架,非同步、快取和訊息中介軟體,分散式和微服務,架構學習和進階等學習資料和文章。