Redis數據結構與全局命令概述

前言

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

 

 

1. Redis高可用概述

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

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

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

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

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

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

2. Redis Sentinel的基本概念

Redis SentinelRedis 高可用 的實現方案。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)、主從切換RedisSentinel 最小配置是 一主一從

RedisSentinel 系統可以用來管理多個 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 實例的時候,會創建 cmdpub/sub 兩個 連接Sentinel 通過 cmd 連接給 Redis 發送命令,通過 pub/sub 連接到 Redis 實例上的其他 Sentinel 實例。

SentinelRedis 主節點從節點 交互的命令,主要包括:

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

SentinelSentinel 交互的命令,主要包括:

命令 作 用
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 同意 主服務器 下線時, 主服務器客觀下線狀態 就會被移除。當 主服務器 重新向 SentinelPING 命令返回 有效回覆 時,主服務器主觀下線狀態 就會被移除。

 

 

 

注意:一個有效的 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 目錄下面。三個配置文件分別對應 masterslave1slave2 三個 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啓動驗證

按順序分別啓動 163792637936379 三個 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-26379redis-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 目錄下面。三個配置文件分別對應 masterslave1slave2 三個 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啓動驗證

按順序分別啓動 163802638036380 三個 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 ID69d05b86a82102a8919231fd3c2d1f21ce86e000,並通過 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 ID21e30244cda6a3d3f55200bcd904d0877574e506,並通過 Sentinel ID 把自身加入 sentinel 集羣中。此時 sentinel 集羣中已有 sentinel-16380sentinel-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 IDfd166dc66425dc1d9e2670e1f17cb94fe05f5fc7,並通過 Sentinel ID 把自身加入 sentinel 集羣中。此時 sentinel 集羣中已有 sentinel-16380sentinel-26380sentinel-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-26379redis-36379,同時寫入了其餘兩個 Sentinel 節點 sentinel-26380sentinel-36380IP 地址,端口號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-26379redis-36379,同時寫入了其餘兩個 Sentinel 節點 sentinel-36380sentinel-16380IP 地址,端口號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-26379redis-36379,同時寫入了其餘兩個 Sentinel 節點 sentinel-16380sentinel-26380IP 地址,端口號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 節點爲 主節點,它的進程 ID7127。爲了模擬 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-36379slaveof 配置更新爲 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 集羣模式 予以解決。


來源:https://juejin.im/post/5bb01064e51d453eb93d8028

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章