什麼是Redis Sentinel
Redis Sentinel是用來實作Redis高可用的一套解決方案。Redis Sentinel由兩個部分組成:由一個或者多個Sentinel執行個體組成Sentinel系統;由一個主Redis伺服器(Master Redis)和多個從Redis伺服器(Slave Redis)組成主從備份的Redis系統。
Sentinel系統本身是一個分布式的系統,它的作用是監視Redis伺服器,在Master Redis下線時,自動将某個Slave Redis提升為新的主伺服器。Redis系統由Master Redis處理用戶端的指令請求,Slave Redis作為主伺服器的備份而存在。
Redis Sentinel主要作用
- 監控(Monitoring):Sentinel 會不斷地檢查你的主伺服器和從伺服器是否運作正常。
- 提醒(Notification):當被監控的某個Redis伺服器出現問題時, Sentinel可以通過API向管理者或者其他應用程式發送通知。
- 自動故障遷移(Automatic failover):當一個主伺服器不能正常工作時, Sentinel會開始一次自動故障遷移操作,它會将失效主伺服器的其中一個從伺服器更新為新的主伺服器,并讓失效主伺服器的其他從伺服器改為複制新的主伺服器;當用戶端試圖連接配接失效的主伺服器時,叢集也會向用戶端傳回新主伺服器的位址,使得叢集可以使用新主伺服器代替失效伺服器。
Redis Sentinel系統架構圖
Sentinel的原理并不複雜:
- 啟動N個Sentinel執行個體,這些Sentinel執行個體會去監控你指定的Redis Master/Slaves。
- 當Redis Master節點挂掉後,Sentinel執行個體通過ping檢測失敗發現這種情況就認為該節點進入 SDOWN狀态,也就是檢測的Sentinel執行個體主觀地(Subjectively)認為該Redis Master節點挂掉。
- 當一定數目(Quorum參數設定的Sentinel執行個體都認為該Master挂掉的情況下,該節點将轉換進入ODOWN狀态,也就是客觀地(Objectively)挂掉的狀态。
- 接下來Sentinel執行個體之間發起選舉,選擇其中一個Sentinel執行個體發起failover過程:從Slave中選擇一台作為新的Master,讓其它Slave從新的Master複制資料,并通過Pub/Sub釋出事件。
- 使用者用戶端從任意Sentinel執行個體擷取Redis配置資訊,并監聽(可選)Sentinel發出的事件: SDOWN, ODOWN以及failover等,并做相應主從切換,Sentinel還扮演了服務發現的角色。
- Sentinel的Leader選舉采用的是Raft協定。
建構Redis Sentinel叢集
Redis Sentinel環境準備
主機名 | IP | 端口号 | 角色 |
---|---|---|---|
dev-master-01 | 192.168.2.210 | 6379/26379 | Redis Master/Sentinel |
dev-node-01 | 192.168.2.211 | ||
dev-node-02 | 192.168.2.212 |
一個一主多從的Redis系統中,可以使用多個Sentinel進行監控任務以保證系統足夠穩健。此時,不僅Sentinel會同時監控主資料庫和從資料庫,Sentinel之間也會互相監控。在這裡,建議大家Sentinel至少部署三個,并且使用奇數個Sentinel。
安裝Redis和Sentinel
在三台伺服器上分别安裝Redis和Sentinel。需要注意的是,如果要給Redis設定密碼,需要在三個Redis的配置檔案中設定相同的密碼。
安裝的Redis版本必須在2.8版本以上。
$ apt-get install redis-server redis-sentinel
配置Redis和Sentinel
配置Redis
三台Redis主機配置類似,隻是初次配置時角色不同。這裡以主機
dev-master-01
為例,其它兩台按實際情況修改就行了。
Redis預設會綁定到
127.0.0.1
,這裡要在多台機器間通信,我們将它綁定到主機IP上。
$ vim /etc/redis/redis.conf
bind 192.168.2.210
如果要給Redis設定密碼,需要在三個Redis的配置檔案中設定相同的密碼。
$ vim /etc/redis/redis.conf
requirepass "000000"
設定主從複制
在兩個Slave Redis的配置檔案中聲明所從屬的主資料庫。
$ vim /etc/redis/redis.conf
slaveof 192.168.2.210 6379
這裡需要注意一點:當一個Master配置需要密碼才能連接配接時,用戶端和Slave在連接配接時都需要提供密碼。Master通過
requirepass
設定自身的密碼,不提供密碼無法連接配接到這個Master。Slave通過
masterauth
來設定通路Master時的密碼。
Sentinel可以切換主從資料庫,主資料庫可能會變成從資料庫,是以三台機器上都需要同時設定
requirepass
和
masterauth
配置項。
$ vim /etc/redis/redis.conf
requirepass "000000"
masterauth "000000"
配置Sentinel
redis-sentinel軟體包中預設包含了一個名為
sentinel.conf
的檔案,預設在
/etc/redis/sentinel.conf
。這裡以主機
dev-master-01
為例,其它兩台配置類似,按實際情況修改就行了。
運作一個Sentinel所需的最少配置如下所示:
$ vim /etc/redis/sentinel.conf
daemonize yes
port 26379
bind 192.168.2.210
sentinel monitor redis-master 192.168.2.210 6379 2
sentinel down-after-milliseconds redis-master 5000
sentinel failover-timeout redis-master 180000
sentinel parallel-syncs redis-master 2
sentinel auth-pass redis-master 000000
sentinel notification-script redis-master /etc/redis/notify.sh
sentinel client-reconfig-script redis-master /etc/redis/failover.sh
logfile /var/log/redis/redis-sentinel.log
以上配置項說明:
-
daemonize yes
以背景程序模式運作。
-
port 26379
Sentinel執行個體之間的通訊端口,該端口号預設為26379。
-
bind 192.168.2.210
Sentinel預設會綁定到
127.0.0.1
-
sentinel monitor redis-master 192.168.2.210 6379 2
Sentinel去監視一個名為redis-master的主伺服器,這個主伺服器的IP位址為192.168.2.210 ,端口号為6379。将這個主伺服器判斷為失效至少需要2個Sentinel同意,一般設定為N/2+1(N為Sentinel總數)。隻要同意Sentinel的數量不達标,自動故障遷移就不會執行。
不過要注意,無論你設定要多少個Sentinel同意才能判斷一個伺服器失效, 一個Sentinel都需要獲得系統中多數Sentinel的支援,才能發起一次自動故障遷移,并預留一個給定的配置紀元。(configuration Epoch ,一個配置紀元就是一個新主伺服器配置的版本号)。
-
sentinel down-after-milliseconds redis-master 5000
down-after-milliseconds
選項指定了Sentinel認為伺服器已經斷線所需的毫秒數。如果伺服器在給定的毫秒數之内,沒有傳回Sentinel發送的PING指令的回複,或者傳回一個錯誤,那麼Sentinel将這個伺服器标記為主觀下線(subjectively down,簡稱SDOWN)。
不過隻有一個Sentinel将伺服器标記為主觀下線并不一定會引起伺服器的自動故障遷移,隻有在足夠數量的Sentinel都将一個伺服器标記為主觀下線之後,伺服器才會被标記為客觀下線(objectively down,簡稱ODOWN), 這時自動故障遷移才會執行。将伺服器标記為客觀下線所需的Sentinel數量由對主伺服器的配置(sentinel monitor參數)決定。
-
sentinel failover-timeout redis-master 180000
如果在多少毫秒内沒有把宕掉的那台Master恢複,那Sentinel認為這是一次真正的當機。在下一次選取時排除該宕掉的Master作為可用的節點,然後等待一定的設定值的毫秒數後再來探測該節點是否恢複,如果恢複就把它作為一台Slave加入Sentinel監測節點群,并在下一次切換時為他配置設定一個”選取号”。
-
sentinel parallel-syncs redis-master 2
parallel-syncs
選項指定了在執行故障轉移時,最多可以有多少個從伺服器同時對新的主伺服器進行同步。這個數字越小,完成故障轉移所需的時間就越長。
如果從伺服器被設定為允許使用過期資料集(
slave-serve-stale-data
選項), 那麼你可能不希望所有從伺服器都在同一時間向新的主伺服器發送同步請求。因為盡管複制過程的絕大部分步驟都不會阻塞從伺服器,但從伺服器在載入主伺服器發來的RDB檔案時,仍然會造成從伺服器在一段時間内不能處理指令請求。
如果全部從伺服器一起對新的主伺服器進行同步,那麼就可能會造成所有從伺服器在短時間内全部不可用的情況出現。你可以通過将這個值設為1來保證每次隻有一個從伺服器處于不能處理指令請求的狀态。
-
sentinel auth-pass redis-master 000000
當Master設定了密碼時,Sentinel連接配接Master和Slave時需要通過設定參數
auth-pass
配置相應密碼。
-
sentinel notification-script redis-master /etc/redis/notify.sh
指定Sentinel檢測到該監控的Redis執行個體failover時調用的報警腳本。腳本被允許執行的最大時間為60秒,超過這個時間腳本會被kill。該配置項可選,但線上系統建議配置。這裡的通知腳本簡單的記錄一下failover事件。
# 建立通知腳本
$ vim /etc/redis/notify.sh
#! /bin/bash
echo "master failovered at `date`" > /var/log/redis/redis_issues.log
# 給腳本增加執行權限
$ chmod +x /etc/redis/notify.sh
-
sentinel client-reconfig-script redis-master /etc/redis/failover.sh
指定Sentinel failover之後重配置用戶端時執行的腳本,該配置項可選,但線上系統建議配置。
-
logfile /var/log/redis/redis-sentinel.log
日志檔案所在位置,預設在/var/log/redis/redis-sentinel.log。
運作Sentinel
配置完Redis和Sentinel之後,按順序啟動各個角色。啟動順序如下:
Master->Slave->Sentinel
,要確定按照這個順序依次啟動。
- 啟動Redis
$ systemctl start redis
- 啟動Sentinel
運作Sentinel有兩種方式:
雖然Redis Sentinel有單獨的軟體安裝包,但實際上它隻是一個運作在特殊模式下的Redis執行個體。目前Redis Stable版已經自帶了redis-sentinel這個工具。你可以在啟動一個普通Redis執行個體時通過給定
--sentinel
選項來啟動Redis Sentinel。
第一種:用單獨的可執行檔案redis-sentinel
$ redis-sentinel /etc/redis/sentinel.conf
第二種:使用redis-server的—sentinel選項
$ redis-server /etc/redis/sentinel.conf --sentinel
以上兩種方式,都必須指定一個Sentinel的配置檔案sentinel.conf。需要確定配置檔案是可寫的,因為Sentinel會往配置檔案裡添加很多資訊作為狀态持久化,這是為了重新開機等情況下可以正确地恢複 Sentinel的狀态。
當配置檔案無法寫入時,Sentinel會啟動失敗。Sentinel預設監聽26379端口,是以運作前必須确定該端口沒有被别的程序占用。
我們這裡用
redis-sentinel
方式來啟動:
$ systemctl start redis-sentinel
- 測試Sentinel
啟動成功後可以通過redis用戶端工具檢視目前Sentinel的資訊,終端輸入:
$ redis-cli -p 26379 -h 192.168.2.210 INFO Sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:2
sentinel_scripts_queue_length:1
master0:name=redis-master,status=ok,address=192.168.2.210:6379,slaves=2,sentinels=1
Sentinel啟動後會輸出類似的日志:
$ tail -f /var/log/redis/redis-sentinel.log
6207:X 06 Jun 10:40:05.904 # Sentinel runid is 2b2446b24a2bd01b9f54a6b2ca4f945a3480dd7e
6207:X 06 Jun 10:40:05.904 # +monitor master redis-master 192.168.2.210 6379 quorum 2
6207:X 06 Jun 10:40:05.910 * +slave slave 192.168.2.211:6379 192.168.2.211 6379 @ redis-master 192.168.2.210 6379
6207:X 06 Jun 10:40:05.915 * +slave slave 192.168.2.212:6379 192.168.2.212 6379 @ redis-master 192.168.2.210 6379
6207:X 06 Jun 12:01:33.098 * +sentinel sentinel 192.168.2.211:26379 192.168.2.211 26379 @ redis-master 192.168.2.210 6379
6207:X 06 Jun 12:02:07.922 * +sentinel sentinel 192.168.2.212:26379 192.168.2.212 26379 @ redis-master 192.168.2.210 637968.2.212:6379 192.168.2.212 6379 @ redis-master 192.168.2.210 6379
輸出的結果表示開始監控redis-master叢集,并輸出叢集的基本資訊。
+slave
+sentinel
分别代表成功發現了從資料庫和其他Sentinel。
- 檢視sentinel.conf
重新打開sentinel.conf檔案,發現Sentinel自動生成了一些資訊,記錄了監控過程中的狀态變化。
$ cat /etc/redis/sentinel.conf
# Generated by CONFIG REWRITE
maxclients 4064
sentinel leader-epoch redis-master 0
sentinel known-slave redis-master 192.168.2.212 6379
sentinel known-slave redis-master 192.168.2.211 6379
sentinel current-epoch 0
- 檢視Sentinel監控的主從伺服器
列出所有被監視的主伺服器,以及這些主伺服器的目前狀态。
$ redis-cli -p 26379 -h 192.168.2.210
192.168.2.210:26379> sentinel master redis-master
1) "name"
2) "redis-master"
3) "ip"
4) "192.168.2.210"
5) "port"
6) "6379"
7) "runid"
8) "02d88a6105ce3277745c1fc65b695887f165f302"
9) "flags"
10) "master"
11) "pending-commands"
12) "0"
13) "last-ping-sent"
14) "0"
15) "last-ok-ping-reply"
16) "1096"
17) "last-ping-reply"
18) "1096"
19) "down-after-milliseconds"
20) "5000"
21) "info-refresh"
22) "4732"
23) "role-reported"
24) "master"
25) "role-reported-time"
26) "667578"
27) "config-epoch"
28) "0"
29) "num-slaves"
30) "2"
31) "num-other-sentinels"
32) "0"
33) "quorum"
34) "2"
35) "failover-timeout"
36) "180000"
37) "parallel-syncs"
38) "2"
39) "notification-script"
40) "/etc/redis/notify.sh"
Sentinel驗證
測試Failover
我們讓dev-master-01主機上的redis-master主動休眠30秒來觀察failover過程:
$ redis-cli -p 6379 -h 192.168.2.210 -a 000000 DEBUG sleep 30
我們可以看到每個Sentinel程序都監控到Master挂掉,從sdown狀态進入odown,然後選舉了一個leader來進行failover,最終
192.168.2.212
成為新的Master, Sentinel的日志輸出:
日志的幾個主要事件
在Redis Master角色上主要有以下幾個事件:
-
,發現Master檢測失敗,主觀認為該節點挂掉,進入sdown狀态。+sdown master redis-master 192.168.2.210 6379
-
,有兩個Sentinel節點認為Master 6379挂掉,達到配置的+odown master redis-master 192.168.2.210 6379 #quorum 2/2
值2,是以認為Master已經客觀挂掉,進入odown狀态。quorum
-
,表示Sentine開始進行故障恢複。+try-failover master redis-master 192.168.2.210 6379
-
,準備選舉一個 Sentinel Leader來開始failover。+vote-for-leader 2b2446b24a2bd01b9f54a6b2ca4f945a3480dd7e 1
-
,表示Sentinel完成故障修複,其中包括了Sentinel Leader的選舉、備選從資料庫的選擇等較為複雜的過程。+failover-end master redis-master 192.168.2.210 6379
-
, 切換Master節點,failover完成。+switch-master redis-master 192.168.2.210 6379 192.168.2.212 6379
-
,192.168.2.210休眠完成後,作為Slave挂載到192.168.2.212後面,可見Sentinel确實同時在監控Slave狀态,并且挂掉的節點不會自動移除,而是繼續監控。-sdown slave 192.168.2.210:6379 192.168.2.210 6379 @ redis-master 192.168.2.212 6379
在Redis Slave角色上主要有以下幾個事件:
Redis Slave上大多數都和Redis Master上的事件類似,不同的是Redis Slave還多了一步配置更新。
-
+config-update-from sentinel 192.168.2.210:26379 192.168.2.210 26379 @ redis-master 192.168.2.210 6379
檢視Sentinel配置檔案變更
經過一次failover後,會發現Sentinel配置檔案變更了以下一些内容。可以看到Sentinel将最新的叢集狀态寫入了配置檔案。
$ cat /etc/redis/sentinel.conf
# Generated by CONFIG REWRITE
maxclients 4064
sentinel leader-epoch redis-master 1
sentinel known-slave redis-master 192.168.2.211 6379
sentinel known-slave redis-master 192.168.2.210 6379
sentinel known-sentinel redis-master 192.168.2.212 26379 bbf85fae74692d9527e77c5b0bb83a2b5db40dd2
sentinel known-sentinel redis-master 192.168.2.210 26379 2b2446b24a2bd01b9f54a6b2ca4f945a3480dd7e
sentinel current-epoch 1
驗證下三台主機上的角色
以下輸出資訊,表明192.168.2.212上的Redis是Master角色。
$ redis-cli -p 6379 -h 192.168.2.212 -a 000000 info Replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.2.211,port=6379,state=online,offset=2312008,lag=0
slave1:ip=192.168.2.210,port=6379,state=online,offset=2312008,lag=0
master_repl_offset:2312008
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1639828
repl_backlog_histlen:672181
以下輸出資訊,表明192.168.2.210上的Redis是Slave角色。
$ redis-cli -p 6379 -h 192.168.2.210 -a 000000 info Replication
# Replication
role:slave
master_host:192.168.2.212
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:2222825
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:593455
repl_backlog_histlen:1048576
以下輸出資訊,表明192.168.2.211上的Redis是Slave角色。
$ redis-cli -p 6379 -h 192.168.2.211 -a 000000 info Replication
# Replication
role:slave
master_host:192.168.2.212
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_repl_offset:2283392
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
Sentinel日常運維
Sentinel常用指令
以下列出的是Sentinel接受的指令:
-
:傳回PONG。PING
-
:列出所有被監視的主伺服器,以及這些主伺服器的目前狀态。SENTINEL masters
-
:用于檢視監控的某個Redis Master資訊,包括配置和狀态等。SENTINEL master <master name>
-
:列出給定主伺服器的所有從伺服器,以及這些從伺服器的目前狀态。SENTINEL slaves <master name>
-
:檢視給定主伺服器的Sentinel執行個體清單及其狀态。SENTINEL sentinels <master name>
-
:傳回給定名字的主伺服器的IP位址和端口号。 如果這個主伺服器正在執行故障轉移操作,或者針對這個主伺服器的故障轉移操作已經完成,那麼這個指令傳回新的主伺服器的IP位址和端口号。SENTINEL get-master-addr-by-name <master name>
-
:重置所有名字和給定模式pattern相比對的主伺服器。pattern 參數是一個Glob風格的模式。重置操作清除主伺服器目前的所有狀态,包括正在執行中的故障轉移,并移除目前已經發現和關聯的,主伺服器的所有從伺服器和Sentinel。SENTINEL reset <pattern>
-
:當主伺服器失效時, 在不詢問其他Sentinel意見的情況下, 強制開始一次自動故障遷移(不過發起故障轉移的Sentinel會向其他Sentinel發送一個新的配置,其他Sentinel會根據這個配置進行相應的更新)。SENTINEL failover <master name>
-
:強制重設所有監控的Master狀态,清除已知的Slave和Sentinel執行個體資訊,重新擷取并生成配置檔案。SENTINEL reset <pattern>
-
:強制發起一次某個Master的failover,如果該Master不可通路的話。SENTINEL failover <master name>
-
:檢測Sentinel配置是否合理,failover的條件是否可能滿足,主要用來檢測你的Sentinel配置是否正常。SENTINEL ckquorum <master name>
-
:強制Sentinel重寫所有配置資訊到配置檔案。SENTINEL flushconfig
-
:一個Sentinel可以通過向另一個Sentinel發送SENTINEL is-master-down-by-addr <ip> <port>
指令來詢問對方是否認為給定的伺服器已下線。SENTINEL is-master-down-by-addr
增加和移除監控以及修改配置參數
SENTINEL MONITOR <name> <ip> <port> <quorum>
SENTINEL REMOVE <name>
SENTINEL SET <name> <option> <value>
增加和移除Sentinel
增加新的Sentinel執行個體非常簡單,修改好配置檔案,啟動即可,其他Sentinel會自動發現該執行個體并加入叢集。如果要批量啟動一批Sentinel節點,最好以30秒的間隔一個一個啟動為好,這樣能確定整個 Sentinel叢集的大多數能夠及時感覺到新節點,滿足當時可能發生的選舉條件。
移除一個Sentinel執行個體會相對麻煩一些,因為Sentinel不會忘記已經感覺到的Sentinel執行個體,是以最好按照下列步驟來處理:
- 停止将要移除的sentinel程序。
- 給其餘的sentinel程序發送
指令來重置狀态,忘記将要移除的sentinel,每個程序之間間隔30秒。SENTINEL RESET *
- 確定所有sentinel對于目前存貨的sentinel數量達成一緻,可以通過
指令來觀察,或者檢視配置檔案。SENTINEL MASTER <mastername>
生産環境推薦
對于一個最小叢集,Redis應該是一個Master帶上兩個Slave,并且開啟下列選項:
min-slaves-to-write 1
min-slaves-max-lag 10
這樣能保證寫入Master的同時至少寫入一個Slave,如果出現網絡分區阻隔并發生failover的時候,可以保證寫入的資料最終一緻而不是丢失,寫入老的Master會直接失敗。
Slave可以适當設定優先級,除了0之外(0表示永遠不提升為Master),越小的優先級,越有可能被提示為Master。如果Slave分布在多個機房,可以考慮将和Master同一個機房的Slave的優先級設定的更低以提升他被選為新的Master的可能性。
考慮到可用性和選舉的需要,Sentinel程序至少為3個,推薦為5個。如果有網絡分區,應當适當分布(比如2個在A機房, 2個在B機房,一個在C機房)等。
用戶端實作
用戶端從過去直接連接配接Redis ,變成:
- 先連接配接一個Sentinel執行個體
- 使用
擷取Redis位址資訊。SENTINEL get-master-addr-by-name master-name
- 連接配接傳回的Redis位址資訊,通過
指令查詢是否是Master。如果是,連接配接進入正常的服務環節。否則應該斷開重新查詢。ROLE
- (可選)用戶端可以通過
來更新自己的Sentinel執行個體清單。SENTINEL sentinels <master-name>
當Sentinel發起failover後,切換了新的Master,Sentinel會發送
CLIENT KILL TYPE normal
指令給用戶端,用戶端需要主動斷開對老的Master的連結,然後重新查詢新的Master位址,再重複走上面的流程。這樣的方式仍然相對不夠實時,可以通過
Sentinel
提供的
Pub/Sub
來更快地監聽到failover事件,加快重連。
如果需要實作讀寫分離,讀走Slave,那可以走
SENTINEL slaves <master name>
來查詢Slave清單并連接配接。