Redis-Sentinel是Redis官方推薦的高可用性(HA)解決方案,當用Redis作Master-slave的高可用方案時,假如master宕機了,Redis自己(包括它的不少客戶端)都沒有實現自動進行主備切換,而Redis-sentinel自己也是一個獨立運行的進程,它能監控多個master-slave集羣,發現master宕機後能進行自動切換。redis
Sentinel 是一個監視器,它能夠根據被監視實例的身份和狀態來判斷應該執行何種動做。
算法
1)監控(Monitoring):
Sentinel會不斷地檢查你的主服務器和從服務器是否運做正常。vim
2)提醒(Notification):
當被監控的某個Redis服務器出現問題時,Sentinel能夠經過API向管理員或者其餘應用程序發送通知。安全
3)自動故障遷移(Automatic failover):
當一個主服務器不能正常工做時,Sentinel會開始一次自動故障遷移操做,它會將失效主服務器的其中一個從服務器升級爲新的主服務器,並讓失效主服務器的其餘從服務器改成複製新的主服務器;當客戶端試圖鏈接失效的主服務器時,集羣也會向客戶端返回新主服務器的地址,使得集羣可使用新主服務器代替失效服務器。服務器
Sentinel經過用戶給定的配置文件來發現主服務器。
網絡
Sentinel會與被監視的主服務器建立兩個網絡鏈接:
命令鏈接用於向主服務器發送命令。
訂閱鏈接用於訂閱指定的頻道,從而發現監視同一主服務器的其餘Sentinel。測試
配置文件示例3d
redis-sentinel sentinel.conf ############ master1 configure ############## sentinel monitor master1 127.0.0.1 6379 2 sentinel down-after-milliseconds master1 30000 sentinel parallel-syncs master1 1 sentinel failover-timeout master1 900000 ############ master2 configure ############## sentinel monitor master2 127.0.0.1 12345 5 sentinel down-after-milliseconds master2 50000 sentinel parallel-syncs master2 5 sentinel failover-timeout master2 450000
Sentinel經過向主服務器發送INFO命令來自動得到全部從服務器的地址。
code
跟主服務器同樣,Sentinel 會與每一個被發現的從服務器建立命令鏈接和訂閱鏈接。server
Sentinel 會經過命令鏈接向被監視的主從服務器發送 「HELLO」 信息,該消息包含 Sentinel 的 IP、端口號、ID 等內容,以此來向其餘 Sentinel 宣告本身的存在。與此同時Sentinel 會經過訂閱鏈接接收其餘 Sentinel 的「HELLO」 信息,以此來發現監視同一個主服務器的其餘 Sentinel 。
1)一個Sentinel能夠與其餘多個Sentinel進行鏈接,各個Sentinel之間能夠互相檢查對方的可用性,並進行信息交換。你無須爲運行的每一個 Sentinel 分別設置其餘 Sentinel 的地址,由於Sentinel能夠經過發佈與訂閱功能來自動發現正在監視相同主服務器的其餘 Sentinel ,這一功能是經過向頻道__sentinel__:hello發送信息來實現的。
2)與此相似,你也沒必要手動列出主服務器屬下的全部從服務器,由於 Sentinel 能夠經過詢問主服務器來得到全部從服務器的信息。每一個Sentinel會以每兩秒一次的頻率,經過發佈與訂閱功能,向被它監視的全部主服務器和從服務器的__sentinel__:hello頻道發送一條信息,信息中包含了Sentinel的IP地址、端口號和運行ID(runid)。
3)每一個Sentinel都訂閱了被它監視的全部主服務器和從服務器的__sentinel__:hello 頻道,查找以前未出現過的sentinel(looking for unknown sentinels)。當一個Sentinel發現一個新的Sentinel時,它會將新的Sentinel添加到一個列表中,這個列表保存了Sentinel已知的,監視同一個主服務器的全部其餘 Sentinel 。Sentinel發送的信息中還包括完整的主服務器當前配置(configuration)。若是一個 Sentinel 包含的主服務器配置比另外一個Sentinel發送的配置要舊,那麼這個 Sentinel 會當即升級到新配置上。
4)在將一個新 Sentinel 添加到監視主服務器的列表上面以前,Sentinel 會先檢查列表中是否已經包含了和要添加的 Sentinel 擁有相同運行 ID 或者相同地址(包括 IP 地址和端口號)的 Sentinel ,若是是的話,Sentinel 會先移除列表中已有的那些擁有相同運行 ID或者相同地址的 Sentinel ,而後再添加新 Sentinel 。
Sentinel之間只會互相建立命令鏈接,用於進行通訊。由於已經有主從服務器做爲發送和接收HELLO信息的中介,因此Sentinel之間不會建立訂閱鏈接。
Sentinel使用PING命令來檢測實例的狀態:若是實例在指定的時間內沒有返回回覆,或者返回錯誤的回覆,那麼該實例會被 Sentinel 判斷爲下線。
Redis的Sentinel中關於下線(down)有兩個不一樣的概念:
1)主觀下線(Subjectively Down, 簡稱 SDOWN)指的是單個 Sentinel 實例對服務器作出的下線判斷。
2)客觀下線(Objectively Down,簡稱 ODOWN)指的是多個Sentinel實例在對同一個服務器作出SDOWN判斷,而且經過SENTINEL is-master-down-by-addr命令互相交流以後,得出的服務器下線判斷。(一個 Sentinel能夠經過向另外一個Sentinel發送SENTINEL is-master-down-by-addr命令來詢問對方是否定爲給定的服務器已下線。)

若是一個服務器沒有在 master-down-after-milliseconds 選項所指定的時間內,對向它送PING命令的Sentinel返回一個有效回覆(valid reply),那麼Sentinel就會將這個服務器標記爲主觀下線。
服務器對PING命令的有效回覆能夠是如下三種回覆的其中一種:
1)返回 +PONG 。
2)返回 -LOADING 錯誤。
3)返回 -MASTERDOWN 錯誤。
若是服務器返回除以上三種回覆以外的其餘回覆,又或者在指定時間內沒有回覆Ping命令,那麼Sentinel認爲服務器返回的回覆無效(non-valid)。
注意:一個服務器必須在master-down-after-milliseconds毫秒內,一直返回無效回覆纔會被Sentinel標記爲主觀下線。
舉個例子,若是master-down-after-milliseconds選項的值爲30000毫秒(30秒),那麼只要服務器能在每29秒以內返回至少一次有效回覆,這個服務器就仍然會被認爲是處於正常狀態的。
從主觀下線狀態切換到客觀下線狀態並無使用嚴格的法定人數算法(strong quorum algorithm),而是使用了流言協議:若是 Sentinel 在給定的時間範圍內,從其餘Sentinel那裏接收到了足夠數量的主服務器下線報告,那麼Sentinel就會將主服務器的狀態從主觀下線改變爲客觀下線。若是以後其餘Sentinel再也不報告主服務器已下線,那麼客觀下線狀態就會被移除。
客觀下線條件只適用於主服務器:對於任何其餘類型的Redis實例,Sentinel在將它們判斷爲下線前不須要進行協商,因此從服務器或者其餘 Sentinel 永遠不會達到客觀下線條件。
只要一個Sentinel發現某個主服務器進入了客觀下線狀態,這個Sentinel就可能會被其餘Sentinel推選出,並對失效的主服務器執行自動故障遷移操做。
一次故障轉移操做由如下步驟組成:
1)發現主服務器已經進入客觀下線狀態。
2)基於Raft leader election協議 ,進行投票選舉
3)若是當選失敗,那麼在設定的故障遷移超時時間的兩倍以後,從新嘗試當選。若是當選成功,那麼執行如下步驟。
4)選出一個從服務器,並將它升級爲主服務器。
5)向被選中的從服務器發送 SLAVEOF NO ONE 命令,讓它轉變爲主服務器。
6)經過發佈與訂閱功能,將更新後的配置傳播給全部其餘Sentinel,其餘Sentinel對它們本身的配置進行更新。
7)向已下線主服務器的從服務器發送SLAVEOF命令,讓它們去複製新的主服務器。
8)當全部從服務器都已經開始複製新的主服務器時, leader Sentinel 終止此次故障遷移操做。

每當一個Redis實例被從新配置(reconfigured)—— 不管是被設置成主服務器、從服務器、又或者被設置成其餘主服務器的從服務器 —— Sentinel 都會向被從新配置的實例發送一個CONFIG REWRITE命令,從而確保這些配置會持久化在硬盤裏。
Sentinel使用如下規則來選擇新的主服務器:
1)在失效主服務器屬下的從服務器當中,那些被標記爲主觀下線、已斷線、或者最後一次回覆PING命令的時間大於五秒鐘的從服務器都會被淘汰。 2)在失效主服務器屬下的從服務器當中,那些與失效主服務器鏈接斷開的時長超過down-after選項指定的時長十倍的從服務器都會被淘汰。 3)在經歷了以上兩輪淘汰以後剩下來的從服務器中,咱們選出複製偏移量(replication offset)最大的那個從服務器做爲新的主服務器;若是複製偏移量不可用,或者從服務器的複製偏移量相同,那麼帶有最小運行ID的那個從服務器成爲新的主服務器。
Sentinel自動故障遷移的一致性特質:
1)Sentinel自動故障遷移使用Raft算法來選舉領頭(leader)Sentinel ,從而確保在一個給定的週期(epoch)裏,只有一個領頭產生。 2)這表示在同一個週期中, 不會有兩個 Sentinel 同時被選中爲領頭,而且各個 Sentinel 在同一個節點中只會對一個領頭進行投票。 3)更高的配置節點老是優於較低的節點,所以每一個 Sentinel 都會主動使用更新的節點來代替本身的配置。 簡單來講,咱們能夠將Sentinel配置看做是一個帶有版本號的狀態。一個狀態會以最後寫入者勝出(last-write-wins)的方式(也便是,最新的配置老是勝出)傳播至全部其餘Sentinel。
舉個例子:
1)當出現網絡分割(network partitions)時,一個Sentinel可能會包含了較舊的配置,而當這個Sentinel接到其餘Sentinel發來的版本更新的配置時,Sentinel就會對本身的配置進行更新。
2)若是要在網絡分割出現的狀況下仍然保持一致性, 那麼應該使用 min-slaves-to-write 選項,讓主服務器在鏈接的從實例少於給定數量時中止執行寫操做,與此同時,應該在每一個運行Redis主服務器或從服務器的機器上運行Redis Sentinel進程。
Sentinel狀態的持久化:
1)Sentinel 的狀態會被持久化在 Sentinel 配置文件裏面。 2)每當Sentinel接收到一個新的配置,或者當領頭Sentinel爲主服務器建立一個新的配置時,這個配置會與配置節點一塊兒被保存到磁盤裏面。 3)這意味着中止和重啓Sentinel進程都是安全的。
Sentinel在非故障遷移的狀況下對實例進行從新配置:
1)即便沒有自動故障遷移操做在進行,Sentinel總會嘗試將當前的配置設置到被監視的實例上面。 特別是: 根據當前的配置,若是一個從服務器被宣告爲主服務器,那麼它會代替原有的主服務器,成爲新的主服務器,而且成爲原有主服務器的全部從服務器的複製對象。 2)那些鏈接了錯誤主服務器的從服務器會被從新配置, 使得這些從服務器會去複製正確的主服務器。 3)不過,在以上這些條件知足以後,Sentinel在對實例進行從新配置以前仍然會等待一段足夠長的時間,確保能夠接收到其餘Sentinel發來的配置更新,從而避免自身由於保存了過時的配置而對實例進行了沒必要要的從新配置。
角色 | 主機 IP | 端口 |
---|---|---|
主庫(master) | db01 | 10.0.0.51 6379 |
從庫(slave01) | db01 | 10.0.0.51 6380 |
主庫(slave02) | db01 | 10.0.0.51 6381 |
#建立sentinel的配置文件目錄 [root@db01 ~]# mkdir /etc/redis/26380 #進入sentinel配置目錄 [root@db01 ~]# cd /etc/redis/26380/ #編輯配置文件 [root@db01 26380]# vim sentinel.conf port 26380 dir "/etc/redis/26380" sentinel monitor mymaster 127.0.0.1 6379 1 sentinel down-after-milliseconds mymaster 5000 #啓動sentinel [root@db01 26380]# redis-sentinel /etc/redis/26380/sentinel.conf &
#鏈接redis主庫 [root@db01 26380]# redis-cli -p 6379 #關閉主庫 127.0.0.1:6379> SHUTDOWN #登陸原從庫6380 [root@db01 26380]# redis-cli -p 6380 #查看主從信息 127.0.0.1:6380> info replication # Replication role:master //因而可知,原從庫6380已經被提高爲主庫 connected_slaves:1 slave0:ip=127.0.0.1,port=6381,state=online,offset=3552,lag=0 //從庫變成了6381 master_repl_offset:3566 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:3565 #開啓舊主庫6379 [root@db01 26380]# redis-server /etc/redis/6379/redis.conf #鏈接舊主庫6379 [root@db01 26380]# redis-cli -p 6379 #查看主從信息 127.0.0.1:6379> info replication # Replication role:slave //角色變成了slave master_host:127.0.0.1 master_port:6380 //主庫的端口是6380 master_link_status:up master_last_io_seconds_ago:2 master_sync_in_progress:0 slave_repl_offset:37819 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 #在新主6380上查看主從信息 [root@db01 26380]# redis-cli -p 6380 127.0.0.1:6380> info replication # Replication role:master connected_slaves:2 slave0:ip=127.0.0.1,port=6381,state=online,offset=45288,lag=1 slave1:ip=127.0.0.1,port=6379,state=online,offset=45421,lag=0 //6379自動加入了集羣 master_repl_offset:45421 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:45420
sentinel monitor mymaster 127.0.0.1 6379 2
Sentinel 去監視一個名爲mymaster的主服務器,這個主服務器的IP地址爲127.0.0.1,端口號爲6379,而將這個主服務器判斷爲失效至少須要2個Sentinel贊成(只要贊成Sentinel的數量不達標,自動故障遷移就不會執行,不過要注意,不管你設置要多少個Sentinel贊成才能判斷一個服務器失效,一個 Sentinel 都須要得到系統中多數(majority) Sentinel 的支持,才能發起一次自動故障遷移,並預留一個給定的配置節點(configuration Epoch,一個配置節點就是一個新主服務器配置的版本號)。換句話說,在只有少數(minority)Sentinel進程正常運做的狀況下,Sentinel 是不能執行自動故障遷移的。
sentinel down-after-milliseconds mymaster 5000
指定了Sentinel認爲服務器已經斷線所需的毫秒數。若是服務器在給定的毫秒數以內,沒有返回Sentinel發送的Ping命令的回覆,或者返回一個錯誤,那麼Sentinel將這個服務器標記爲主觀下線(subjectively down,簡稱SDOWN)。不過只有一個Sentinel將服務器標記爲主觀下線並不必定會引發服務器的自動故障遷移:只有在足夠數量的Sentinel都將一個服務器標記爲主觀下線以後,服務器纔會被標記爲客觀下線(objectively down, 簡稱 ODOWN ),這時自動故障遷移纔會執行。
sentinel failover-timeout mymaster 180000
自動故障切換的超時時間
sentinel parallel-syncs mymaster 1
在執行故障轉移時,最多能夠有多少個從服務器同時對新的主服務器進行同步,這個數字越小,完成故障轉移所需的時間就越長。若是從服務器被設置爲容許使用過時數據集(參見對 redis.conf 文件中對 slave-serve-stale-data 選項的說明),那麼你可能不但願全部從服務器都在同一時間向新的主服務器發送同步請求,由於儘管複製過程的絕大部分步驟都不會阻塞從服務器,但從服務器在載入主服務器發來的 RDB 文件時,仍然會形成從服務器在一段時間內不能處理命令請求:若是所有從服務器一塊兒對新的主服務器進行同步,那麼就可能會形成全部從服務器在短期內所有不可用的狀況出現。能夠經過將這個值設爲1來保證每次只有一個從服務器處於不能處理命令請求的狀態。
#鏈接sentinel管理端口 [root@db01 26380]# redis-cli -p 26380 #檢測狀態,返回PONG 127.0.0.1:26380> PING PONG #列出全部被監視的主服務器 127.0.0.1:26380> SENTINEL masters #列出全部被監視的從服務器 127.0.0.1:26380> SENTINEL slaves mymaster #返回給定名字的主服務器的IP地址和端口號 127.0.0.1:26380> SENTINEL get-master-addr-by-name mymaster 1) "127.0.0.1" 2) "6380" #重置全部名字和給定模式 127.0.0.1:26380> SENTINEL reset mymaster #當主服務器失效時,在不詢問其餘Sentinel意見的狀況下,強制開始一次自動故障遷移。 127.0.0.1:26380> SENTINEL failover mymaster