本文永久地址:http://www.javashuo.com/article/p-yobvqtmc-e.htmlhtml
Redis官方文檔 https://redis.io/topics/sentinel#redis-sentinel-documentationgit
Redis Sentinel(Sentinel)用於爲Redis提供高可用性,這就意味着使用sentinel能建立一個故障時不須要人工當即參與修復的環境。此外,sentinel還能實現其餘的功能,如監控,提醒,爲客戶端提供配置( monitoring, notifications and acts as a configuration provider for clients.)。github
·監控(Monitoring):sentinel會不間斷地檢查Redis master和Redis slave是否正常運行redis
·提醒(Notification):當其中一個被監控的Redis實例出現問題,sentinel能經過API或其餘程序通知管理員算法
·自動故障轉移(Automatic failover):當Redis master故障不能正常工做時,sentinel會故障切換進程,將一個slave提高爲master,另外的Redis slave將更新配置使用新的master,此後有新鏈接時,會鏈接到新的Redis masterdocker
·配置提供者(Configuration provider):Redis充當客戶端服務發現的權威來源:客戶端鏈接到sentinel,以請求當前可靠的Redis master地址,若發生故障轉移,sentinels將報告新地址數組
Redis sentinel是一個分佈式系統,能夠在一個架構中運行多個sentinel進程,優點以下:緩存
· 當多個sentinels肯定master再也不可用,就進行故障檢測,這下降了誤報的可能性安全
· 當在不一樣服務器上運行多個sentinel進程,而後將sentinel作集羣,即便其中一個故障,也能夠進行熱切換,下降對客戶端的影響,從而提高了系統健壯性服務器
· Redis客戶端可鏈接任意sentinel來使用Redis集羣
Sentinel當前版本被稱爲sentinel 2,它是使用更強大和更簡單的預測算法(在本文檔中進行了解釋)重寫了最初的Sentinel實現。自Redis 2.8版本,Redis sentinel發佈了穩定版本。Redis Sentinel版本1與Redis 2.6一塊兒發佈,但已棄用,不建議使用
Sentinel 程序是redis編譯安裝完成後src目錄下的「redis-sentinel」文件
使用redis-sentinel啓動:
redis-sentinel sentinel.conf
使用redis-server以sentinel模式啓動:
redis-server sentinel.conf --sentinel
· Sentinel運行默認偵聽端口26379
· 運行sentinel必須指定配置文件,由於系統使用此文件來保存當前狀態,一遍重啓sentinel時從新加載。指定的配置文件有問題或不指定配置文件,sentinel會拒絕啓動;
· 至少三個sentinel實例才能提高系統健壯性,由於自動故障轉移時,必須有剩餘大多數sentinels存活,且sentinels間能互相通訊
· 三個sentinel實例應放在相對獨立的虛擬機,甚至物理機,甚至不一樣區域
· 因爲Redis使用異步複製,sentinel+Redis不能保證故障期間保留已確認的寫入,但可配置sentinel容許丟失有限的寫入。另外還有一些安全性較低的部署方式
· 使用的客戶端要支持sentinel,大多數熱門的都支持sentinel,但不是所有
· 沒有徹底健壯的HA設置,因此要常常在測試環境中測試
· sentinel在docker、端口映射或網絡地址轉換的環境中配置要格外當心: 在從新映射端口的狀況下,真實端口可能與轉發的端口不一樣,會破壞Sentinel自動發現其餘的sentinel進程和master的slave列表。
Redis安裝完成會生成Redis根目錄下的sentinel.conf配置文件,最小配置以下:
bind 0.0.0.0 #偵聽地址
port 26379 #默認偵聽端口
dir /tmp #sentinel工做目錄
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5
僅須指定masters去監控,每一個不一樣的master都應該有不一樣的名稱 ,因爲slave是自動發現的,因此不必指定,且sentinel會自動更新全部slave的狀態,信息等到配置文件,以便在從新啓動時保留信息。每次進行故障轉移,slave被提高爲master時,每當有新sentinel被發現時,配置都會被重寫。
上面兩組示例配置主要監控兩組redis實例,每一個實例由一個master和未知數量的從節點組成,一組實例集合調用「mymaster」,另外一組調用「resque」
Sentinel monitor語法:
sentinel monitor <master-group-name> <ip> <port> <quorum>
· master-group-name:Redis master實例名稱
· ip,port:master IP、master PORT
· quorum:將master判斷爲失效至少須要N個Sentinel贊成,僅用於檢測master鏈接失敗。如redis集羣中有5個sentinel實例,若這裏的票數是2,master掛掉,表示有2個sentinel認爲master掛掉才能被認爲是真正的掛掉,此時會觸發自動故障轉移。其中sentinel集羣中各個sentinel也能經過gossip協議互相通訊。這意味着在故障期間,若大多數sentinel進程間沒法互相通訊,自動故障轉移將不會被觸發(aka no failover in the minority partition)。
那上述例子第一組Redis實例監控的master叫「mymaster」,鏈接地址爲127.0.0.1:6379,當sentinel集羣中有2個實例認爲mymaster掛掉時,自動進行故障轉移。
上述最小配置中其它選項幾乎老是下面形式:
sentinel <option_name> <master_name> <option_value>
用於配置如下參數:
· down-after-milliseconds
若服務器在給定的毫秒數以內, 沒有返回Sentinel發送的PING命令的回覆,或者返回一個錯誤, 那麼Sentinel將這個服務器標記爲主觀下線(subjectively down,簡稱SDOWN)。
不過只有一個Sentinel將服務器標記爲主觀下線並不必定會引發服務器的自動故障遷移:只有在足夠數量的Sentinel都將一個服務器標記爲主觀下線以後, 服務器纔會被標記爲客觀下線(objectively down,簡稱ODOWN),這時自動故障遷移纔會執行。
將服務器標記爲客觀下線所需的Sentinel數量由對master的配置決定
· parallel-sync
選項指定了在執行故障轉移時,最多能夠有多少個slave同時對新的master進行異步複製(併發數量),這個數字越小,完成故障轉移所需的時間就越長(數字越小,同時能進行復制的slave越少)。
若slave被設置爲容許使用過時數據集或未更新的數據集(參見redis.conf中對slave-serve-stale-data選項的說明),那麼架構上可能不但願全部的slave與新master同一時間進行異步複製,由於儘管slave與master間的複製過程絕大部分步驟不會阻塞slave,但slave在載入master發來的RDB文件時,仍然會形成slave在一小段時間內不能處理命令,若是所有slave一塊兒對新master進行異步複製,那麼會形成全部slave在短期內所有不可用的狀況。
固然可設置該值爲1來保證每次只有一個slave與新 master進行異步複製,且不能處理命令。
· failover-timeout
故障轉移的超時時間 failover-timeout(默認三分鐘)能夠用在如下這些方面:
· 同一個sentinel對同一個master兩次failover之間的間隔時間。
· 當一個slave從一個錯誤的master那裏異步複製數據開始計算時間,直到slave被糾正爲向正確的master那裏複製數據時。
· 當想要取消一個正在進行的failover所須要的時間。
· 當進行failover時,配置全部slaves指向新的master所需的最大時間。不過,即便過了這個超時,slaves依然會被正確配置爲指向master,可是就不按parallel-syncs所配置的規則來了
當在Redis實例中開啓了requirepass foobared 受權密碼 這樣全部鏈接Redis實例的客戶端都要提供密碼
設置哨兵sentinel 鏈接主從的密碼 注意必須爲主從設置同樣的驗證密碼
sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
本文檔剩餘的內容將對Sentinel系統的其餘選項進行介紹, 示例配置文件sentinel.conf也對相關的選項進行了完整的註釋。
到目前爲止,已經瞭解了sentinel基本信息,接下來將經過一系列示例來說解架構中須要多少sentinel進程,如何放置sentinel進程。首先是一些說明:
· Masters表示爲:M一、M二、M3...Mn
· Slaves表示爲:R一、R二、R3...Rn(R stands for replica)
· Sentinels表示爲:S一、S二、S3...Sn
· Clientis表示爲:C一、C二、C3...Cn
· 當一個實例因Sentinel動做而改變角色時,咱們把它放在方括號內,因此[M1]表示因爲Sentinel干預而成爲master的實例
要注意的是,至少三個sentinel實例才能提高系統健壯性,由於自動故障轉移時,必須有剩餘大多數sentinels存活,且sentinels間能互相通訊
· 此種架構中,若master M1故障,2個sentinel徹底能夠就故障打成一致,而後受權自動進行故障切換,此時仍然正常的R1將被提高爲master [M1]
· 但,若M1所在的系統故障宕機,S1也會中止工做,另外一系統中運行的sentinel將沒法受權故障轉移,所以整個Redis集羣將沒法使用
要注意,多數sentinel存活是必要的,主要應對不一樣的故障轉移場景,而後將最新的配置信息發到至其餘全部的sentinels。且,在沒有任何投票協商的狀況下,進行自動故障轉移是很是危險的:
上圖中,兩系統網絡鏈接出現問題,會產生兩個徹底同樣的master(假設S2未經投票協商自動進行故障切換),外部客戶端會無休止的向兩邊寫入同時數據,自此M1與[M1]得到的數據可能會有差別,當網絡恢復正常時,Redis實例將沒法判斷哪份數據是正確的。此爲腦裂。所以,至少在三個獨立的系統中配置三個sentinel,以此解決腦裂的問題
基於3個獨立系統,每一個系統都運行一個redis進程和sentinel進程
若master M1故障,S2和S3會就故障達成一致,發起投票,提高一個slave爲新master,且自動切換故障,所以客戶端能繼續請求Redis集羣
Sentinel和redis進程一樣也是異步複製,當M1所在系統網絡出現問題,斷開與R2,R3的鏈接。假設爲主寫從讀架構,那麼在M1上確認了的寫入請求將沒法複製到slave(或者被提高爲master的slave),以下圖:
此時,舊的master M1被網絡隔離,所以slave R2被提高爲master M2,然而與舊masterM1鏈接的客戶端(如C1)將會繼續寫入舊數據。當鏈接恢復正常後,且舊master M1將更新配置,成爲新master的slave,且丟棄全部數據集,重新master更新數據,如此便丟棄了鏈接斷開期間客戶端寫入到M1的數據
使用Redis複製功能選項能緩解此問題,該功能容許在master檢測到再也不能將寫入操做複製到指定數量的slave時中止寫入操做。
min-slaves-to-write 1
min-slaves-max-lag 10
最少與1個slave正常通訊且延遲小於10s才能接收客戶端寫入操做(複製是異步的,所以不能寫入實際上意味着slave已斷開鏈接,或者未發送超過指定max-lag秒數的異步確認)。
使用此配置,上例中Redis 舊master M1將在10s後不可用。
但,此配置是一把雙刃劍,當兩個slave關掉或者掛掉,master將中止接收寫入請求,整個架構將變得只讀。
有時只有兩個服務器可用於運行Redis實例,一主一從。例二中的配置在這個場景中不可用,所以咱們將sentinel放在客戶端系統上:
此架構中,sentinel與客戶端同樣,若大多數客戶端均可以訪問master,那就沒毛病。C一、C二、C3在這裏表示通用客戶端,如rails應用程序或者一個應用程序服務器。
若M1和S1所在服務器系統掛掉,將開始故障切換,但不一樣的網絡區域將會致使不一樣的行爲,如客戶端和Redis服務器間的網絡斷開,則sentinel將沒法提高slave爲新的master,此時Redismaster和Redis slave都將不可用。
注意:若C3與M1是運行在同一系統 (hardly possible with the network described above, but more likely possible with different layouts, or because of failures at the software layer),有一個相似於例二中所描述的問題,區別在於不會產生腦裂,因爲只有一主一從,且配置了min-slaves-to-write和min-slaves-max-lag,此時,master必需要能同時接受write/read請求,不然master與slave斷開鏈接達到必定時間後,master將變的不可寫,只可讀。
So this is a valid setup but the setup in the Example 2 has advantages such as the HA system of Redis running in the same boxes as Redis itself which may be simpler to manage, and the ability to put a bound on the amount of time amasterinto the minority partition can receive writes.
若客戶端服務器不足3個,那如今所描述的配置在例三中就不在適用了,此處咱們要混合配置,以下:
與例三環境相似,但此處在四個系統都運行了sentinel,若master M1系統掛掉,其餘三個sentinel將執行故障切換。理論上能夠移除C二、S4,且設置quorum爲2,然而此時應用層就會沒有高可用了
Docker使用端口映射技術:docker容器中運行的程序使用的端口可能會與暴露的端口不一樣,這對於在同一服務器中同時使用相同端口運行多個容器頗有用。
NAT技術中也可能存在端口映射,甚至是IP。
從新映射IP或端口會產生兩個問題:
· sentinel的自動發現再也不工做,由於sentinel經過hello包通告給其餘sentinel本身的偵聽信息(端口+IP)。Sentinel是沒法識別IP或端口是否被從新映射的,所以錯誤的通告信息用於sentinel間鏈接會失敗。
· Redis master命令「INFO」輸出slave的鏈接信息,該鏈接信息用於master用於檢測遠程鏈接,端口或地址是slave自身廣播過來的,然而這個端口多是錯,沒法用於master與slave間通訊,就像上面一點那樣。
在docker環境下,sentinel使用master「INFO」輸出信息自動檢測slave,檢測到的slave將不可達,且sentinel沒法爲master進行故障切換,由於從sentinel和master的角度看,沒有一個slave是正常的。Sentinel也沒法監控這組運行在docker中的master實例,除非配置docker爲1:1的端口映射。
對於第一個問題,若場景需求要在網絡映射環境下運行Redis實例或者sentinel實例,你可使用如下兩個sentinel配置來強制sentinel公佈一個IP和端口:
sentinel announce-ip <ip>
sentinel announce-port <port>
請注意,Docker可以在主機聯網模式下運行(請查看--net=host選項以獲取更多信息)。這應該不會形成任何問題,由於在此設置中不會從新映射端口。
Redis中的sentinel有兩個關於下線(down)的概念:
· 主觀下線(Subjectively Down, 簡稱 SDOWN)指的是單個Sentinel實例對服務器作出的下線判斷。
· 客觀下線(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會將此服務器標記爲主觀下線(SDOWN)
服務器對PING命令的有效回覆能夠是三種中的一種:
· 返回+PONG
· 返回-LOADING錯誤
· 返回-MASTERDOWN錯誤
除此三種外的回覆或者指定時間內沒有回覆,sentinel都會標記該服務器回覆無效(non-vaild)
注意,一個服務器必須在「master-down-after-milliseconds」週期時間(毫秒)返回無效回覆纔會被sentinel標記爲主觀下線,如若「master-down-after-milliseconds」爲30000ms(30s),只要服務器在每29秒以內返回至少一次有效回覆,此服務器就會被認爲處於正常狀態。
從主觀下線狀態切換到客觀下線狀態並無使用嚴格的法定人數算法(strong quorum algorithm),而是使用了流言協議:若是Sentinel在給定的時間範圍內, 從其餘Sentinel那裏接收到了足夠數量的master下線報告, 那麼Sentinel就會將master的狀態從主觀下線改變爲客觀下線。 若是以後其餘Sentinel再也不報告master已下線, 那麼客觀下線狀態就會被移除
客觀下線條件只適用於master:對於任何其餘類型的Redis實例,Sentinel在將它們判斷爲下線前不須要進行協商,因此slave或者其餘Sentinel永遠不會達到客觀下線條件
分爲兩部分,第一部分選出sentinel leader,第二部分進行故障轉移:
一、sentinel集羣中的一個sentinel發現master疑似下線,標記該master的狀態爲主觀下線(SDOWN)【sentinel節點會每1s向master發送PING消息,若一個服務器沒有在「master-down-after-milliseconds」選項指定時間內,對向他發送「PING」的sentinel返回一個有效回覆(valid reply),那麼sentinel會將此服務器標記爲主觀下線(SDOWN)】
二、選出sentinel leader。該sentinel查看本身有無投給其餘sentinel節點票,若已經投過,那麼在兩倍故障轉移超時時間內不會成爲leader,則轉換身份爲follower;沒有投過票則申請成爲leader(Candidate)。【Sentinel集羣正常運行時,每一個節點epoch(版本號,具體是什麼翻看本文章上下文)相同,當須要故障轉移時會在sentinel集羣中選出leader,由leader發起並執行故障轉移操做。Sentinel採用Raft協議實現了Sentinel間選舉Leader的算法(不過也不徹底同樣,具體參看http://weizijun.cn/2015/04/30/Raft協議實戰之Redis%20Sentinel的選舉Leader源碼解析/),Sentinel集羣故障轉移完成後,全部Sentinel又會恢復平等。Leader僅僅是故障轉移操做纔會出現的角色】
三、Candidate(申請成爲leader的sentinel節點)此時更新故障轉移狀態爲「start」,使當前epoch自增1(進入新的選舉週期),給本身投一票以及向其餘sentinel節點請求投票等
四、Candidate不斷統計本身的票數,當達到一半且超過它配置的quorum的票數,那麼它就成爲Leader(若在一個選舉時間內,Candidate沒有得到超過一半且超過它配置的quorum的票數,這次選舉失敗,那麼在設定的故障遷移超時時間的兩倍以後, 從新嘗試當選)
五、sentinel leader迭代全部的sentinel follower節點,檢測是否須要將該master標記爲客觀下線(ODOWN)狀態,是則繼續,不然取消選舉投票
六、選出合適的slave,sentinel leader使用如下流程來選擇合適的slave:
a、 ·在故障master屬下的slave當中, 那些被標記爲主觀下線、已斷線、或者最後一次回覆PING命令的時間大於五秒鐘的slave都會被淘汰
·在故障master屬下的slave當中, 那些與失效master鏈接斷開的時長超過 down-after 選項指定的時長十倍的slave都會被淘汰
b、選擇「slave-priority」(slave優先級)最高的slave,存在則選取該slave成爲新master,存在相同優先級則繼續向下
c、複製偏移量(replication offset,即複製數據最完整)最大的那個slave做爲新master,存在相同複製偏移量則繼續向下
d、選擇「run_id」(「INFO SERVER」查看)最小的slave
七、sentinel leader向被選中的slave發送命令「SLAVEOF NO ONE」,提高選中的slave爲master
八、經過發佈與訂閱功能,將更新後的配置傳播給全部其餘Sentinel, 其餘Sentinel對它們本身的配置進行更新
九、向已下線master的slave發送「SLAVEOF」命令,讓它們重新master複製數據
十、當全部slave都已經開始複製新master時,sentinel leader 終止此次故障遷移操做,全部Sentinel又會恢復平等身份
每當一個 Redis 實例被從新配置(reconfigured) —— 不管是被設置成master、slave、又或者被設置成其餘master的slave ——Sentinel都會向被從新配置的實例發送一個 CONFIG REWRITE 命令, 從而確保這些配置會持久化在硬盤裏。
Redis實例有配置參數「slave-priority」,此參數在「INFO」中也能查詢,sentinel使用此配置從slave來挑選故障切換後的新master:
· 「slave-priority」設置爲0的slave,不能升級爲master
· 優先級小的salve會優先考慮提高爲master。如master有2個slave(S1,S2),優先級S1爲10,S2爲100,若master故障且S1,S2均可用,則S1將是新master首選
當一個sentinel leader實例準備進行故障轉移,因爲master處於ODOWN狀態,且sentinel leader從已知的大多數sentinel實例收到故障轉移受權,此時一個合適的slave就要被選舉出來。slave選舉考量如下幾項:
· 與master斷開時間
· slave優先級
· 複製偏移量
· 運行ID
一個Slave若被發現與master斷開鏈接的時間超過master配置的超時時間(down-after-milliseconds選項)的十倍,加上從正在執行故障轉移的sentinel leader角度看master不可用的時間,將被認爲是不合適的且會被跳過。
即slave若不可用時間超過如下時間,會被認爲是不適合成爲master的節點:
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
經過了以上測試的slave會繼續進行如下篩選:
一、而後按照slave配置文件中「slave-priority」的大小進行排序,數字小且不爲0的slave將被選擇爲新master
二、若「slave-priority」相同,則檢查slave的複製偏移量,偏移量大(從舊master接收到更多的數據)的會被選擇爲新master
三、若多個slave有相同的優先級和複製偏移量,則則選擇「run_id」(INFO SERVER能夠查看到)小的slave成爲新master
在Redis集羣中,如有合適的機器做爲slave,強烈建議將其優先級數配置小一點,使其優先級高一些。另外,複製偏移量相同的狀況並很多見,且全部的redis實例均可以運行在默認「run_id」上,想一想多麼可怕...
· 每一個Sentinel以每秒鐘一次的頻率向它所知的master、slave以及其餘Sentinel實例發送一個PING命令。
· 若是一個實例(instance)距離最後一次有效回覆PING命令的時間超過 down-after-milliseconds 選項所指定的值, 那麼這個實例會被Sentinel標記爲主觀下線。 一個有效回覆能夠是:+PONG、-LOADING或-MASTERDOWN
· 若是一個master被標記爲主觀下線, 那麼正在監控這個master的全部Sentinel要以每秒一次的頻率確認master的確進入了主觀下線狀態
· 若是一個master被標記爲主觀下線, 而且有足夠數量的Sentinel(至少要達到配置文件指定的數量)在指定的時間範圍內贊成這一判斷, 那麼這個master被標記爲客觀下線
· 在通常狀況下, 每一個Sentinel會以每 10 秒一次的頻率向它已知的全部master和slave發送 INFO 命令。 當一個master被Sentinel標記爲客觀下線時,Sentinel向下線master的全部slave發送INFO命令的頻率會從10秒一次改成每秒一次
· 當沒有足夠數量的Sentinel贊成master已經下線master的客觀下線狀態就會被移除。 當master從新向Sentinel的PING命令返回有效回覆時, master的主管下線狀態就會被移除
當Lua腳本運行時間超過配置的Lua腳本時限時,Redis實例將返回「-BUSY」錯誤,在觸發故障切換前,Redis嘗試發送一個「SCRIPT KILL」命令嘗試殺死腳本執行進程,若腳本只讀(the script was read-only),命令將執行成功。若該實例在嘗試後仍處於錯誤狀態,實例將進行故障切換
接下來,將逐步介紹全部關於sentinel API,配置和語義。同時,本節也將會介紹如何配置3個sentinel實例並與之交互。
此處假設3個實例運行在端口5000,5001,5002,且有redis集羣一主一從,分別運行在端口6379,6380,而後這些端口所有偵聽在一個機器的127.0.0.1迴環地址
3個sentinel配置相似:
port 5000
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
其餘兩個sentinel配置修改端口爲5001,5002便可
以上:
· Master實例組定義爲mymaster。依據不一樣的master實例組名稱,sentinel能同時監控不一樣的Redis主從集羣
· quorum設置爲2,sentinel monitor配置指令的最後一個參數值
· down-after-milliseconds值爲5000ms,即5s,所以只要在這段時間沒有收到master的ping回覆,master就會被認定爲鏈接失敗
啓動sentinel會收到Redis集羣登陸消息:
+monitormastermymaster 127.0.0.1 6379 quorum 2
此爲sentinel事件信息,也可以使用「發佈/訂閱」接收這類事件。在故障檢測和故障轉移期間,sentinel會生成並記錄不一樣的事件
查詢sentinel中master的狀態:
redis-cli -p 5000Sentinelmaster mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6379"
7) "runid"
8) "8f315c998236a332cb327e6c33e5efead00f14c9"
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) "368"
19) "last-ping-reply"
20) "368"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "2704"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "1318596"
29) "config-epoch"
30) "2"
31) "num-slaves"
32) "1"
33) "num-other-sentinels"
34) "2"
35) "quorum"
36) "2"
37) "failover-timeout"
38) "180000"
39) "parallel-syncs"
40) "1"
一些關鍵信息:
· num-other-sentinels爲2,表示sentinel檢測到其他兩個sentinel。在日誌中也會看到+sentinel生成的事件
· flags只有master,若master掛掉,那能夠在這看到s_down或o_down標記
· num-slaves爲1,表示sentinel檢測到有一個slave鏈接到master
sentinel查看slave信息
sentinel slaves mymaster
查看sentinel信息
sentinel sentinels mymaster
獲取當前master的地址
SENTINEL get-master-addr-by-name mymaster
故障轉移測試
此時,sentinel測試環境已部署好,能夠暫時關閉master並檢查配置是否發生改變,可讓master暫停300s:
redis-cli -p 6379 DEBUG sleep 300
此命令將master休眠300s,模擬了master故障沒法鏈接的狀況。此時查看sentinel日誌,能看到相關操做:
· 每一個sentinel檢測到master +sdown事件
· 事件後來升級到+odown,意味着多個sentinel確認master不可達
· sentinel投票支持將啓動第一次故障轉移嘗試的sentinel
· 開始故障轉移
· ...
此時再次查詢master地址信息,會獲得不一樣的回覆:
127.0.0.1:5000>Sentinelget-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6380
當master增長安全性被配置爲須要客戶端密碼進行鏈接時,slave也要知道該密碼,以便master與slave用於異步複製協議的主從鏈接。
使用如下指令配置密碼:
· requirepass在master中配置,配置後可確保不處理未驗證客戶端的請求
· masterauth在slave配置,以便slave與master進行身份驗證,正常的複製數據
當使用sentinel模式時,架構中並不僅有一個master,那麼依據sentinel機制,故障轉移後,slave會改變角色成爲新master,舊master恢復正常後會成爲新master的slave,所以上述配置要在全部Redis集羣中實例配置,不管是master仍是slave。
然而,在少數狀況下,咱們可能須要謀個slave節點不須要驗證就可被客戶端讀取數據,能夠經過設置此slave優先級爲0,來避免該slave升級爲master,且僅配置「masterauth」,此時就可實現未經身份驗證的客戶端讀取數據
爲了使sentinel能正常鏈接到配置了「requirepass」的Redis實例,sentinel必須配置「sentinel auth-pass」指令,格式以下:
sentinel auth-pass <master-group-name> <pass>
Sentinel須要明確的客戶端支持,除非系統配置爲執行將全部請求透明重定向到新的主實例(虛擬IP或其餘相似系統)的腳本。Sentinel客戶端指南中介紹了客戶端庫實現的主題
Sentinel提供一個API來檢查其狀態,檢查受監控master和slave的運行狀態,訂閱以得到特定通知,並在運行時更改sentinel配置
默認sentinel偵聽在TCP端口26379(6379是Redis master和Redis slave端口),sentinel使用redis協議通訊,所以可以使用redis-cli與sentinel進行交互
能夠直接從sentinel的監控信息中查看Redis實例狀態,也能查詢到其餘sentinel的信息等,同時,使用PUB/SUB可 從sentinel接收推送通知,如故障轉移或進入錯誤狀態的實例,均可以進行推送。
如下是命令列表,但不包括修改sentinel配置的命令(稍後介紹)
PING #返回PONG
SENTINEL masters #顯示全部被監控的master集齊狀態
SENTINELmaster<master name> #顯示指定的master的狀態信息
SENTINEL slaves <master name> #顯示指定的master的slave狀態信息
SENTINEL sentinels <master name> #顯示指定master的sentinel狀態信息
SENTINEL get-master-addr-by-name <master name> #顯示指定名稱master的IP和PORT,若master正在進行故障切換或被中止,則返回被提高爲master的slave的IP和PORT
SENTINEL reset <pattern> #重置全部包含關鍵字的master。 「pattern」參數是一個全局風格的模式。重置進程會清除master全部先前保存的狀態(包括正在進行故障切換),且刪除已發現並與master關聯的每一個slave及其狀態
SENTINEL failover <master name> #手動強制故障切換,當master失效時,在不詢問其餘Sentinel意見的狀況下, 強制開始一次自動故障遷移(不過發起故障轉移的Sentinel會向其餘Sentinel發送一個新的配置,其餘Sentinel會根據這個配置進行相應的更新)
SENTINEL ckquorum <master name> #檢查當前sentinel的配置可否達到故障切換master所需的數量,執行此命令也會檢測其餘大多數sentinel是否正常(檢測是否在線,以及是否能受權故障切換)。此命令應在sentinel中用於檢測sentinel部署是否正常
SENTINEL flushconfig #強制sentinel將運行時配置寫入磁盤,包括當前sentinel狀態。通常,sentinel每次在其狀態改變時都會重寫配置(在sentinel狀態信息被持久化到磁盤後重啓)。然而,有時會出現配置文件丟失的狀況,如操做失誤,磁盤故障,軟件包升級或配置管理器而致使配置文件丟失。此時,強制sentinel重寫配置文件就很必要了,也很方便(老的配置文件丟失不會影響該命令的執行)
從Redis 2.8.4版開始,sentinel提供一個API來添加、刪除或更改master的配置。注意:如有多個sentinel,你應該手動把全部的改變同步到其餘Redis sentinel實例中,意思是更改單個sentinel配置,不會自動將更改同步到網絡中的sentinels。
如下是sentinel用於更新sentinel實例配置的命令列表:
SENTINEL MONITOR <name> <ip> <port> <quorum> #此命令通知sentinel開始監控一個新的master,且指定其名稱,ip,port,quorum,與sentinel.conf配置文件裏「sentinel monitor」指令語法相似,不一樣的是你不能使用主機名代替IP,只能使用IPv4或IPv6地址
SENTINEL REMOVE <name> #移除指定master:這個master將從sentinel監控列表移除,將從sentinel的內部狀態信息中徹底清除,sentinel,masters也沒法列出該master
SENTINEL SET <name> <option> <value> #與「CONFIG SET」命令類似,用於改變特定master的配置參數。指定多「option/value」對是能夠的(單對也是能夠的);sentinel.conf裏全部可配置參數均可以使用SET命令進行配置。
如下是SENTINEL SET命令的一個示例,用於修改所down-after-milliseconds調用的主設備的配置objects-cache:
SENTINEL SET objects-cache-master down-after-milliseconds 1000
如前所述,sentinel SET可用來所設置全部配置文件中可配置的配置參數,此外,他能在不從新添加master(先SENTINEL REMOVE再SENTINEL MONITOR)的狀況下,修改quorum:
SENTINEL SET objects-cache-master quorum 5
請注意,因爲SENTINEL MASTER以簡單解析格式(做爲字段/值對數組)提供全部配置參數,所以沒有等效的GET命令
基於sentinel自動發現機制,添加一個新sentinel是很是簡單的。你須要僅僅是啓動新的sentinel,配置危機監控當前全部活動的master,10s內sentinel將得到其餘sentinel列表及被監控master的全部slave信息
若要添加多個sentinel
建議一個一個添加,等待其餘sentinels已經能和新sentinel通訊,再添加下一個。新增sentinel有可能失敗,一個一個添加sentinel能有效保證大多數sentinel都是正常的(若一次性添加的sentinel數量大於現有sentinel數量,而且添加出現問題,可能會致使現有sentinel出現問題)。通常的每30s添加一個sentinel是比較常見的。
添加結束後,可用命令「SENTINELmastermastername」檢查全部sentinel是否已經徹底獲取到全部master的信息
刪除sentinel比較複雜
即便被刪除的sentinel很長時間沒法訪問,sentinels不會徹底清除已經添加過的sentinels信息,由於要儘可能減小其餘sentinel的配置版本的更新,刪除sentinel也有可能引發故障轉移
所以爲了移除一個sentinel,在沒有網絡隔離的狀況下應遵循如下步驟:
一、中止要刪除的sentinel進程
二、執行命令「SENTINEL RESET *」,向全部其餘sentinel實例發送命令重置狀態信息(*表示重置全部master,也能夠指定master名稱)。信息會一個一個的更新,大概須要30s
三、執行命令「SENTINELmastermastername」檢查每一個sentinel顯示的sentinel數量是否一致
刪除舊的master或沒法沒法訪問的slave
Sentinel不會徹底清除指定master的slave,即便slave長時間沒法訪問。在故障轉移後,一旦舊master再次可用,會自動成爲新master(舊slave)的slave,此時,新master和新slave會組成新的複製架構。
若想從sentinel監控的master/slave列表裏永久刪除一個slave(多是舊master),在中止slave進程後,你須要向全部sentinel發送命令「SENTINEL RESET mastername」,重置mastername全部狀態信息
客戶端能夠將sentinel看作一個只提供了訂閱功能的Redis服務器,不能使用PUBLISH命令向這個服務器發送信息,但可以使用「SUBSCRIBE」命令或「PSUBSCRIBE」命令,經過訂閱給定的頻道來獲取相應的事件提醒。
一個頻道能接收和此頻道名稱相同的事件,如名爲+sdown的頻道就可接收全部實例進入主觀下線(SDOWN)狀態的事件
經過執行「PSUBSCRIBE *」命令能接收全部事件信息。
如下是能利用此API接收的頻道和消息格式的列表。第一個英文單詞是頻道/事件的名稱,其他是數據格式。
注意,當格式中包含「instance details」時,表示頻道所返回信息中包含了如下用於識別目標實例的內容:、
<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>
「@」字符串後的內容指定master(即@到最後部分,此部分是可選的),僅在「@」字符以前的內容指定的實例不是master時使用。
· +reset-master <instance details> #master已被重置
· +slave <instance details> #一個新slave已被sentinel識別並關聯
· +failover-state-reconf-slaves <instance details> #故障轉移狀態切換到了reconf-slaves狀態
· +failover-detected <instance details> #另外一個sentinel開始了一次故障轉移操做,或一個slave轉換成了master
· +slave-reconf-sent <instance details> #領頭(leader)的sentinel向實例發送了命令「SLAVEOF」,爲實例從新設置新的Redis master
· +slave-reconf-inprog <instance details> #實例正在將本身設置爲master的slave,但相應的同步過程仍未完成
· +slave-reconf-done <instance details> #slave已成功完成對新master的同步
· -dup-sentinel <instance details> #對給定master進行監控的一個或多個sentinel已經由於重複出現而被移除(當sentinel實例重啓時會出現此種狀況)
· +sentinel <instance details> #master有新sentinel被識別並添加
· +sdown <instance details> #指定實例現處於主觀下線Subjectively Down狀態
· -sdown <instance details> #指定實例現再也不處於主觀下線狀態
· +odown <instance details> #指定實例現處於客觀下線(Objectively Down)狀態
· -odown <instance details> #指定實例現再也不處於客觀下線狀態
· +new-epoch <instance details> #Slot的版本號或者消息的版本號已被更新。節點如何判斷收到的集羣消息是較新的。Redis中使用版本號機制來判斷消息的新舊,版本號越高表示消息越新。在Redis中這種版本號被稱做configEpoch,每一個節點都有一個configEpoch,它是一個64位的整數。其實configEpoch更應該被稱做是Slot的版本號,或者某個Slot與節點映射關係的版本號。怎麼理解呢?咱們從消息衝突的角度看這個問題,由於configEpoch就是爲了解決消息衝突的嘛。如上文所說集羣中每一個節點都會維護一份集羣狀態快照。快照中每一個Slot都有一個與之對應的節點,每一個節點都有一個configEpoch,因此直觀上configEpoch就像是Slot的版本號。當某一個節點負責的Slot有變化的時候,節點會更新本身的configEpoch,並隨着集羣心跳傳播該消息,集羣消息是一系列Slot、節點與configEpoch組成的三元組。當新的集羣消息傳播到其它節點的時候,節點會對比節點自己與集羣消息中對應Slot的configEpoch來決定是否更新本地集羣狀態快照,從這層意義上看configEpoch也更適合被稱做Slot的版本號或者消息的版本號。
· +try-failover <instance details> #正在進行新的故障轉移,正處於等待多數選舉狀態
· +elected-leader <instance details> #贏得指定版本的選舉,能夠進行故障遷移
· +failover-state-select-slave <instance details> #故障轉移操做現處於「select-slave」狀態,sentinel正在尋找一個能被提高爲master的slave
· no-good-slave <instance details> #sentinel未找到合適的slave去升級。Sentinel會在一段時間後重試,可是在這種狀況下,可能會改變狀態機並終止故障切換
· selected-slave <instance details> #sentinel找到合適的slave去提高
· failover-state-send-slaveof-noone <instance details> #sentinel正在講指定的slave提高爲master,等待功能升級完成
· failover-end-for-timeout <instance details> #故障轉移因超時而停止,不過最終全部slave都會開始複製新master(slaves will eventually be configured to replicate with the newmasteranyway)
· failover-end <instance details> #故障轉移操做順利完成,全部slave開始重新master複製數據
· switch-master <master name> <oldip> <oldport> <newip> <newport> #master鏈接配置變動,外部客戶端都關心的信息
· +tilt #進入tilt模式
· -tilt #退出tilt模式
哨兵與其餘哨兵保持聯繫,以便互相檢查對方的可用性,並進行信息交換。無須爲運行的每一個Sentinel分別設置其餘Sentinel的地址, 由於Sentinel能夠經過發佈與訂閱功能來自動發現正在監控相同master的其餘Sentinel, 這一功能是經過向頻道 sentinel:hello 發送信息來實現的。
與此相似, 你也沒必要手動列出master屬下的全部slave, 由於Sentinel能夠經過詢問master來得到全部slave的信息。
· 每一個Sentinel會以每兩秒一次的頻率, 經過發佈與訂閱功能,向被它監控的全部master和slave的 sentinel:hello 頻道發送一條信息,信息中包含了Sentinel的 IP 地址、端口號和運行 ID (runid)。
· 每一個Sentinel都訂閱了被它監控的全部master和slave的 sentinel:hello 頻道, 查找以前未出現過的Sentinel(looking for unknown sentinels)。當一個Sentinel發現一個新的Sentinel時, 它會將新的Sentinel添加到一個列表中, 這個列表保存了Sentinel已知的, 監控同一個master的全部其餘Sentinel。
· Sentinel 發送的信息中還包括完整的master當前配置(configuration)。 若是一個Sentinel包含的master配置比另外一個Sentinel發送的配置要舊, 那麼這個Sentinel會當即升級到新配置上。
· 在將一個新Sentinel添加到監控master的列表上面以前,Sentinel會先檢查列表中是否已經包含了和要添加的Sentinel擁有相同運行 ID 或者相同地址(包括 IP 地址和端口號)的Sentinel, 若是是的話,Sentinel會先移除列表中已有的那些擁有相同運行 ID 或者相同地址的Sentinel,而後再添加新Sentinel。
即便沒有自動故障遷移操做在進行,sentinel總會嘗試將當前配置應用到被監控的實例上,特別是:
· 依據當前配置,若一個slave被提高爲master,那他會成爲舊master原有slave的複製對象,鏈接了錯誤master的slave會被從新配置,以便能從正確的master獲取數據
· 舊master掛掉從新上線後,會被配置爲新master的slave
不過, 在以上這些條件知足以後,sentinel在對實例進行從新配置以前仍然會等待一段足夠長的時間, 確保能夠接收到其餘sentinel發來的配置更新, 從而避免自身由於保存了過時的配置而對實例進行了沒必要要的從新配置
Quorum
如前所述,每一個被sentinel監控的master都配置了quorum,指定須要對master的不可達性或故障達成一致的sentinel數量,以便觸發故障轉移。另外,網絡問題致使架構間產生網絡分區,此時故障轉移毫不會在只有小部分的Sentinels存在的網絡分區中執行,只會在大部分sentinels存在的網絡分區中執行
簡單的說就是:
· quorum:爲了將master標記爲ODOWN,須要發現並確認錯誤的sentinel數量
· 故障轉移在ODOWN狀態被觸發
· 一旦故障轉移被觸發,嘗試進行故障轉移的sentinel會請求大多數sentinel的受權(在quorum爲大多數的狀況下)
如,架構中有5個sentinel 實例,quorum爲2,那麼至少2個sentinel確認master不可達後,故障轉移纔會被觸發,而後能執行故障轉移的只有其中一個sentinel。
若quorum爲5,則全部sentinel都必須就master故障達成一致,且執行故障轉移的sentinel leader要獲得全部sentinel的受權才能進行故障轉移。
這意味着quorum可有兩種方式調整sentinel:
· 若quorum設置爲小於部署的大多數sentinel的數量,此時sentinel對master故障更加敏感,且一旦少數的sentinel沒法和master通訊就會觸發故障轉移
· 若quorum設置爲大於部署的大多數sentinel的數量,此時只有大多數sentinel都確認master故障時,sentinel leader才能開始故障轉移
爲了開始故障轉移,Sentinels leader須要從大多數sentinel獲得受權,緣由:
當一個Sentinel leader被受權,它會爲故障轉移後的新master得到一個惟一性的epoch,用來標記故障轉移完成後sentinels的新配置版本號,另外,只有確認了master故障的大多數sentinel才能得到這個版本號。這意味着,每次故障轉移的配置都會更新一個獨一無二的版本號,這很重要,後面會解釋爲何這麼重要。
此外Sentinels有機制:若一個sentinel爲故障轉移一個新master而投票給其餘sentinel,它將等待一段時間再次嘗試故障轉移這個master,在sentinel.conf中可配置這個延遲時間failover-timeout。這意味着Sentinels在相同的時間內不會嘗試故障轉移相同的master,第一次請求受權成功後會嘗試,失敗則另外一個sentinel將會在一段時間後嘗試,類推。
Redis Sentinel保證了活性(liveness)特色:若是大多數Sentinels 可以互相通訊,master故障,最後必定會有一個sentinel會被受權開始故障轉移。
Redis Sentinel一樣也保證了安全(safety)特色:一次故障轉移中,每一個Sentinel故障轉移同一個master將使用不一樣的epoch版本號,失敗後由另外的sentinel會從新生成惟一的epoch版本號,而後發起故障轉移;而第一次生成的epoch版本號由於沒有故障轉移成功而丟棄,生成的配置也不是最終配置也會被丟棄
一旦sentinel leader 故障轉移成功,他將開始廣播新的配置,以便其餘sentinels更新新master的信息。
爲了確認故障轉移是否成功,sentinel須要能發送命令「SLAVEOF NO ONE」給全部參與選舉的slave,稍後,切換爲新master的信息能在「INFO」輸出中顯示。
此時,即便slave正在更新配置,故障轉移也被斷定爲成功,且全部Sentinels須要開始報告新的配置。
Sentinel leader傳播新配置的緣由是每一個sentinel每次進行已受權的故障轉移時,都會產生不一樣的惟一的配置版本號,最終全部sentinel會共享一個配置版本號。
每一個sentinel使用redis 訂閱/發佈功能向全部的master/slave連續地廣播其監控的master的版本,同時全部的sentinel也會等待來自其餘sentinel廣播的消息。
配置在__sentinel__:hello發佈/訂閱頻道中被廣播。
每份配置都有不一樣的版本號,而大的版本號老是賽過小的版本號,版本號越大,越接近最終的配置版本,越有廣播的意義。
如,初始配置時,全部sentinels都持有版本號爲1的配置,即mymaster的配置爲192.168.1.50:6379,一段時間後發生故障轉移,生成配置版本號2,若轉移成功,他將廣播新的配置,即192.168.1.51:9000,其餘sentinel實例收到這個配置的廣播會更新的本身的配置,由於此配置有更高的版本號。
也就是說,sentinel有第二個活性特色:一個能互相通訊的sentinel集羣,在故障轉移時,都會嘗試更新版本更高的配置。
通常若網絡故障產生網絡分區,每一個分區的sentinel都會嘗試收斂到更高版本的配置,沒有網絡分區時,全部sentinel都會更新配置
Redis sentinel配置保證最終一致性,產生網絡分區時,每一個分區都會嘗試收斂到更高版本的可用配置。
使用sentinel時,有三種角色:
· Redis實例
· Sentinel實例
· Client
爲定義整個架構系統的行爲,咱們要考慮到上述三種角色,如下網絡中有3個節點,每節點運行一個Redis實例和sentinel實例:
在此係統的初始狀態中,Redis3是master,Redis2和Redis3是slave。此時網絡故障形成舊master與其餘節點隔離,sentinel 1和 2開始一輪故障轉移,提高redis1爲新master。
此時,Sentinel的機制保證了sentinel 1和 2持有master的最新配置,然而sentinel 3在隔離分區中仍然持有舊的配置,咱們知道sentinel 3會在網絡恢復時獲取新的配置,但如有客戶端在網絡故障時訪問舊master,會發生什麼?
此時客戶端仍然能在Redis3(舊master)中寫入,當網絡恢復,Redis3將變成Redis1的slave,並清除在網絡故障期間寫入的全部數據。
依據數據需求,或者配置需求,你可能想或不想數據丟失的狀況發生:
· 若你使用Redis做爲緩存服務器,Client B仍然可向舊master寫入數據是很方便的,即便數據最終會丟失
· 若你使用Redis做爲存儲服務器,這就很不友好了,此時爲了阻止這個問題須要對系統進行配置
因爲Redis是異步複製的,這種狀況下沒法徹底避免數據丟失,但可以使用如下配置限制Redis3和Redis1之間數據的一致性問題:
min-slaves-to-write 1
min-slaves-max-lag 10(秒)
當master配置以上選項,若它不能向至少一個slave寫入數據,將會中止接受寫入請求。因爲是異步複製,不能寫意味着slave已斷開鏈接,或未發送異步確認超過max-lag秒數
所以上例中,redis3將在10s後不可用,網絡恢復後,sentinel 3將會整合到新架構中,客戶端B能從新獲取有效配置並繼續請求。
總之,Redis+Sentinel造成的架構系統具備最終一致性(a whole are a an eventually consistent system where the merge function is last failover wins),且舊master的數據會被丟棄,而後重新mastar從新獲取數據,所以總有一個節點會丟失部分已經寫入的數據。 This is due to Redis asynchronous replication and the discarding nature of the "virtual" merge function of the system。但這sentinel自己沒有限制,若你使用強一致性的方法協調故障轉移,問題一樣會出現。
只有兩種方法避免丟失已確認的寫入:
· 使用同步複製(以及使用一個合適的一致性算法來運行復制行爲)
· 使用具備最終一致性的系統,能合併相同對象的不一樣版本
Redis如今不能使用上面的任何系統,是目前的發展目標。但是有一個代理實現解決方案2在Redis存儲之上,如SoundCloud Roshi,或者Netflix Dynomite。
Sentinel狀態信息持久化到sentinel.conf中,如每次接收一個新配置文件或者建立一個新配置文件(sentinel leader完成),配置都會和配置版本號(epoch)一塊兒持久化到磁盤。很明顯,即便即便sentinel進程重啓也能保證配置不丟失
Redis sentinel嚴重依賴系統時間:爲了確認實例是否可用,他會記錄最後一次回覆PING的時間,並和當前時間比較推斷距離最後一次回覆過去了多久。
然而,若系統時間發生非正常改變,或者系統很是繁忙,或進程因爲某些緣由阻塞,sentinel可能會出現一些問題
TITL模式是一種特殊的「保護」模式,sentinel能在發生一些意料以外問題時,進入這個模式,下降對系統的依賴。Sentinel定時器中斷正常狀況下每秒10次調用,因此能猜想在定時器中斷的兩次調用之間或多或少會有100毫秒的時間。
Sentinel所作的就是記錄以前的中斷調用時間,並和當前調用時間對比:
· 若是兩次調用時間之間的差距爲負值, 或者很是大(超過 2 秒鐘), 那麼 Sentinel 進入 TILT 模式。
· 若是 Sentinel 已經進入 TILT 模式, 那麼 Sentinel 延遲退出 TILT 模式的時間。
當處於TITL模式,sentinel或持續監控全部狀態,但:
· 中止處理請求
· 當有實例向這個Sentinel發送「SENTINEL is-master-down-by-addr」命令時,Sentinel返回負值: 由於這個Sentinel所進行的下線判斷已經再也不準確。
若是 TILT 能夠正常維持30秒鐘, 那麼Sentinel退出TILT模式。