本文永久地址:https://www.cnblogs.com/erbiao/p/9156215.html Redis官方文檔 https://redis.io/topics/sentinel#redis-sentinel-documentation Redis Sentinel(Sentinel)用 ...
本文永久地址:https://www.cnblogs.com/erbiao/p/9156215.html
Redis官方文檔 https://redis.io/topics/sentinel#redis-sentinel-documentation
Redis Sentinel(Sentinel)用於為Redis提供高可用性,這就意味著使用sentinel能創建一個故障時不需要人工立即參與修複的環境。此外,sentinel還能實現其他的功能,如監控,提醒,為客戶端提供配置( monitoring, notifications and acts as a configuration provider for clients.)。
Redis sentinel功能
·監控(Monitoring):sentinel會不間斷地檢查Redis master和Redis slave是否正常運行
·提醒(Notification):當其中一個被監控的Redis實例出現問題,sentinel能通過API或其他程式通知管理員
·自動故障轉移(Automatic failover):當Redis master故障不能正常工作時,sentinel會故障切換進程,將一個slave提升為master,另外的Redis slave將更新配置使用新的master,此後有新連接時,會連接到新的Redis master
·配置提供者(Configuration provider):Redis充當客戶端服務發現的權威來源:客戶端連接到sentinel,以請求當前可靠的Redis master地址,若發生故障轉移,sentinels將報告新地址
Sentinel的分散式特性
Redis sentinel是一個分散式系統,可以在一個架構中運行多個sentinel進程,優勢如下:
· 當多個sentinels確定master不再可用,就進行故障檢測,這降低了誤報的可能性
· 當在不同伺服器上運行多個sentinel進程,然後將sentinel做集群,即使其中一個故障,也可以進行熱切換,降低對客戶端的影響,從而提升了系統健壯性
· Redis客戶端可連接任意sentinel來使用Redis集群
關於sentinel版本
Sentinel當前版本被稱為sentinel 2,它是使用更強大和更簡單的預測演算法(在本文檔中進行瞭解釋)重寫了最初的Sentinel實現。自Redis 2.8版本,Redis sentinel發佈了穩定版本。Redis Sentinel版本1與Redis 2.6一起發佈,但已棄用,不建議使用
Sentinel 程式是redis編譯安裝完成後src目錄下的“redis-sentinel”文件
啟動sentinel
使用redis-sentinel啟動:
redis-sentinel sentinel.conf
使用redis-server以sentinel模式啟動:
redis-server sentinel.conf --sentinel
部署Redis sentinel前要瞭解
· Sentinel運行預設偵聽埠26379
· 運行sentinel必須指定配置文件,因為系統使用此文件來保存當前狀態,一遍重啟sentinel時重新載入。指定的配置文件有問題或不指定配置文件,sentinel會拒絕啟動;
· 至少三個sentinel實例才能提升系統健壯性,因為自動故障轉移時,必須有剩餘大多數sentinels存活,且sentinels間能互相通信
· 三個sentinel實例應放在相對獨立的虛擬機,甚至物理機,甚至不同區域
· 由於Redis使用非同步複製,sentinel+Redis不能保證故障期間保留已確認的寫入,但可配置sentinel允許丟失有限的寫入。另外還有一些安全性較低的部署方式
· 使用的客戶端要支持sentinel,大多數熱門的都支持sentinel,但不是全部
· 沒有完全健壯的HA設置,所以要經常在測試環境中測試
· sentinel在docker、埠映射或網路地址轉換的環境中配置要格外小心: 在重新映射埠的情況下,真實埠可能與轉發的埠不同,會破壞Sentinel自動發現其他的sentinel進程和master的slave列表。
配置sentinel
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也對相關的選項進行了完整的註釋。
Redis sentinel部署實例
到目前為止,已經瞭解了sentinel基本信息,接下來將通過一系列示例來講解架構中需要多少sentinel進程,如何放置sentinel進程。首先是一些說明:
· Masters表示為:M1、M2、M3...Mn
· Slaves表示為:R1、R2、R3...Rn(R stands for replica)
· Sentinels表示為:S1、S2、S3...Sn
· Clientis表示為:C1、C2、C3...Cn
· 當一個實例因Sentinel動作而改變角色時,我們把它放在方括弧內,所以[M1]表示由於Sentinel干預而成為master的實例
要註意的是,至少三個sentinel實例才能提升系統健壯性,因為自動故障轉移時,必須有剩餘大多數sentinels存活,且sentinels間能互相通信
例一:2個獨立系統,2個sentinel,2節點redis集群(1主1從)的情況(不建議的方案)
· 此種架構中,若master M1故障,2個sentinel完全可以就故障打成一致,然後授權自動進行故障切換,此時仍然正常的R1將被提升為master [M1]
· 但,若M1所在的系統故障宕機,S1也會停止工作,另一系統中運行的sentinel將無法授權故障轉移,因此整個Redis集群將無法使用
要註意,多數sentinel存活是必要的,主要應對不同的故障轉移場景,然後將最新的配置信息發到至其他所有的sentinels。且,在沒有任何投票協商的情況下,進行自動故障轉移是非常危險的:
上圖中,兩系統網路連接出現問題,會產生兩個完全一樣的master(假設S2未經投票協商自動進行故障切換),外部客戶端會無休止的向兩邊寫入同時數據,自此M1與[M1]獲得的數據可能會有差異,當網路恢復正常時,Redis實例將無法判斷哪份數據是正確的。此為腦裂。因此,至少在三個獨立的系統中配置三個sentinel,以此解決腦裂的問題
例二:3個獨立系統,3個sentinel,3節點redis集群(1主2從)的情況(能保證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將停止接收寫入請求,整個架構將變得只讀。
例三:sentinel與客戶端運行在一個系統
有時只有兩個伺服器可用於運行Redis實例,一主一從。例二中的配置在這個場景中不可用,因此我們將sentinel放在客戶端系統上:
此架構中,sentinel與客戶端一樣,若大多數客戶端都可以訪問master,那就沒毛病。C1、C2、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.
例四:sentinel運行在每個系統,redis集群(一主一從),兩個應用層客戶端
若客戶端伺服器不足3個,那現在所描述的配置在例三中就不在適用了,此處我們要混合配置,如下:
與例三環境類似,但此處在四個系統都運行了sentinel,若master M1系統掛掉,其他三個sentinel將執行故障切換。理論上可以移除C2、S4,且設置quorum為2,然而此時應用層就會沒有高可用了
Sentinel,docker,NAT以及可能的問題
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,第二部分進行故障轉移:
1、sentinel集群中的一個sentinel發現master疑似下線,標記該master的狀態為主觀下線(SDOWN)【sentinel節點會每1s向master發送PING消息,若一個伺服器沒有在“master-down-after-milliseconds”選項指定時間內,對向他發送“PING”的sentinel返回一個有效回覆(valid reply),那麼sentinel會將此伺服器標記為主觀下線(SDOWN)】
2、選出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僅僅是故障轉移操作才會出現的角色】
3、Candidate(申請成為leader的sentinel節點)此時更新故障轉移狀態為“start”,使當前epoch自增1(進入新的選舉周期),給自己投一票以及向其他sentinel節點請求投票等
4、Candidate不斷統計自己的票數,當達到一半且超過它配置的quorum的票數,那麼它就成為Leader(若在一個選舉時間內,Candidate沒有獲得超過一半且超過它配置的quorum的票數,此次選舉失敗,那麼在設定的故障遷移超時時間的兩倍之後, 重新嘗試當選)
5、sentinel leader迭代所有的sentinel follower節點,檢測是否需要將該master標記為客觀下線(ODOWN)狀態,是則繼續,否則取消選舉投票
6、選出合適的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
7、sentinel leader向被選中的slave發送命令“SLAVEOF NO ONE”,提升選中的slave為master
8、通過發佈與訂閱功能,將更新後的配置傳播給所有其他Sentinel, 其他Sentinel對它們自己的配置進行更新
9、向已下線master的slave發送“SLAVEOF”命令,讓它們從新master複製數據
10、當所有slave都已經開始複製新master時,sentinel leader 終止這次故障遷移操作,所有Sentinel又會恢復平等身份
每當一個 Redis 實例被重新配置(reconfigured) —— 無論是被設置成master、slave、又或者被設置成其他master的slave ——Sentinel都會向被重新配置的實例發送一個 CONFIG REWRITE 命令, 從而確保這些配置會持久化在硬碟里。
Slave優先順序
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首選
Slave選舉
當一個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會繼續進行以下篩選:
1、然後按照slave配置文件中“slave-priority”的大小進行排序,數字小且不為0的slave將被選擇為新master
2、若“slave-priority”相同,則檢查slave的複製偏移量,偏移量大(從舊master接收到更多的數據)的會被選擇為新master
3、若多個slave有相同的優先順序和複製偏移量,則則選擇“run_id”(INFO SERVER可以查看到)小的slave成為新master
在Redis集群中,若有合適的機器作為slave,強烈建議將其優先順序數配置小一點,使其優先順序高一些。另外,複製偏移量相同的情況並不少見,且所有的redis實例都可以運行在預設“run_id”上,想想多麼可怕...
每個sentinel都需要定期執行的任務
· 每個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的主管下線狀態就會被移除
“-BUSY”狀態處理
當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
Sentinel和Redis認證
當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客戶端實施
Sentinel需要明確的客戶端支持,除非系統配置為執行將所有請求透明重定向到新的主實例(虛擬IP或其他類似系統)的腳本。Sentinel客戶端指南中介紹了客戶端庫實現的主題
Sentinel API
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命令
以下是命令列表,但不包括修改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是非常簡單的。你需要僅僅是啟動新的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,在沒有網路隔離的情況下應遵循以下步驟:
1、停止要刪除的sentinel進程
2、執行命令“SENTINEL RESET *”,向所有其他sentinel實例發送命令重置狀態信息(*表示重置所有master,也可以指定master名稱)。信息會一個一個的更新,大概需要30s
3、執行命令“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所有狀態信息
Pub/Sub消息
客戶端可以將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和slave
哨兵與其他哨兵保持聯繫,以便互相檢查對方的可用性,併進行信息交換。無須為運行的每個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在非故障轉移的情況下對實例進行重新配置
即使沒有自動故障遷移操作在進行,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才能開始故障轉移
配置版本號(epoch)
為了開始故障轉移,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同樣也保證了