????redis哨兵模式是redis高可用模式中的一種方案他可以;從前一篇文章“主從數(shù)據(jù)拷貝”,我們可以知道,在多實例場景下,redis提供了數(shù)據(jù)同步的機制,但是,如果在主從模式下,主節(jié)點異常,那么整個redis服務(wù)實例只能提供查詢服務(wù),而不能夠進行數(shù)據(jù)更新操作,除非有認(rèn)為的干預(yù),使程序恢復(fù);

????上圖為redis哨兵模式的部署圖;從上圖中,我們可以看出,在哨兵模式下,至少需要一個sentinel(哨兵)實例和多個redis運行實例節(jié)點;
? ?1、 sentinel實例的作用為監(jiān)視其他redis運行實例;定時發(fā)送消息給各個redis運行實例,檢測運行實例的狀態(tài),以及發(fā)送消息給與其有關(guān)聯(lián)的其他sentinel實例,獲取他們監(jiān)控的實例的狀態(tài);從上體可以看出來,同一個redis運行實例節(jié)點可以有至少一個sentinel實例監(jiān)視;各個sentilel實例之間相互關(guān)聯(lián),相互交換監(jiān)控數(shù)據(jù)。
? ? 2、拋開sentinel實例看,可以看出各個運行實例其實是一個主從復(fù)制模式下的redis運行環(huán)境;redis運行實例分為兩大類,master節(jié)點和slave節(jié)點,master節(jié)點進行數(shù)據(jù)的修改和數(shù)據(jù)查詢,slave節(jié)點復(fù)制master節(jié)點的數(shù)據(jù),并對外提供查詢功能;
sentinel模式是redis的一種高可用方案,他可以在mstaer節(jié)點異常的時候,自動感知到并且從該master節(jié)點的從slave節(jié)點中自動選出一個節(jié)點,將他升級為master節(jié)點,繼續(xù)進行工作,當(dāng)異常節(jié)點恢復(fù)后,sentinel實例能夠?qū)惓9?jié)點設(shè)置成新選舉出來的master節(jié)點的slave節(jié)點;
????如此一來對外用戶將感知不到redis運行實例中有節(jié)點異常過,以上是sentiel模式的總體思想;
? ? 接下來我們來分析一下程序的流程:
1、sentinel實例如何知道有哪些redis實例需要監(jiān)控呢?
? ? a、來自于sentinel模式的特有配置文件,在主配置文件開啟sentinel模式之后,服務(wù)啟動首先會識別到已經(jīng)開啟sentinel模式,這個時候,程序啟動會去替換命令處理方法,使用sentinel特有的命令處理方法;在然后,程序會讀取sentinel特有的配置文件,將配置文件中配置的節(jié)點信息讀取出來,存儲在內(nèi)存中,并且設(shè)置好主觀下線超時時間等關(guān)鍵信息;
? ? b、另一部分信息來至于sentinel實例向被監(jiān)控節(jié)點發(fā)送info消息時,接收到info消息的被監(jiān)控節(jié)點會將本節(jié)點中所有的關(guān)聯(lián)的實例信息發(fā)送給sentinel實例,sentinel實例在收到響應(yīng)消息后,將其更新到自己維護的實例節(jié)點中;
? ? c、還有一部分來自于節(jié)點的訂閱;sentinel模式下,節(jié)點在啟動的時候回都會想monitor訂閱hello消息,其他的節(jié)點在發(fā)生某種事件(包含節(jié)點的加入和刪除)后,會發(fā)送通知消息,這樣,訂閱過消息的節(jié)點就會收到對應(yīng)的通知,如此就能夠?qū)⒐?jié)點信息相互傳播。
?2、sentinel實例是如何做到自動的維護redis主從節(jié)點的呢?
? ? sentinel模式在經(jīng)過初始化之后,接下來所有的處理都是在定時器中完成;接下來我們分析一下sentinel定時器的處理流程:
????sentinel定時器的諸路口函數(shù)為sentinelTimer,該函數(shù)在redis定時器serverCron函數(shù)中被調(diào)用,每100ms調(diào)用一次;
????接下來首先會判斷sentinel實例是否進入到TITL模式,該模式是sentinel進行的自我檢測,為了防止對redis節(jié)點的誤判斷,當(dāng)sentinel檢測到自己進入到TITL模式下之后,依然會收集信息被監(jiān)視節(jié)點的信息,但不會進行狀態(tài)判斷和修改;
? ? TITL自檢結(jié)束之后,調(diào)用sentinelHandleDictOfRedisInstances方法,遍歷整個sentinel監(jiān)控的節(jié)點,以判斷節(jié)點的健康狀態(tài);在sentinelHandleRedisInstance方法中。首先判斷sentinel節(jié)點與被檢測節(jié)點是否建立連接,如果沒有檢測連接,則創(chuàng)建連接,本節(jié)點與被每個被檢測節(jié)點有量條連接,一條稱之為cc(command connect),另一條稱之為pc(publish command),sentinel節(jié)點與其他關(guān)聯(lián)節(jié)點以及被檢測節(jié)點的連接創(chuàng)建時基于hiredis下的接口創(chuàng)建的異步連接;
????在連接建立成功之后,當(dāng)被檢測節(jié)點不是關(guān)聯(lián)sentinel實例,并且沒有發(fā)送過info消息或者上一個info消息已經(jīng)超時,sentinel會向被檢測節(jié)點發(fā)送info消息,被檢測節(jié)點在收到請求消息后其關(guān)聯(lián)的節(jié)點信息發(fā)送給sentinel節(jié)點,sentinel節(jié)點獲取到響應(yīng)消息后,更新消息收到消息的時間并將響應(yīng)消息解析,已更新他自己維護的被檢測節(jié)點的信息(sentinelInfoReplyCallback方法);當(dāng)不滿足info消息發(fā)送的條件下,會依次檢測是否需要發(fā)送ping消息和publish消息;發(fā)送這些消息就是為獲取被檢測節(jié)點的信息,同時可以更新節(jié)點通信信息,為后續(xù)的檢測做準(zhǔn)備;這些功能sentinelSendPeriodicCommands方法中實現(xiàn);
? ? 在獲取到節(jié)點信息之后,需要檢測節(jié)點是否是主觀下線(站在本sentinel節(jié)點的角度,依賴剛才被檢測節(jié)點信息獲取時更新的時間,進行判斷);在判斷主觀下線時,首先獲取到目前為止,本節(jié)點與被檢測節(jié)點上次通信的時間間隔,然后分別檢測cc連接和pc連接是否是正常的,當(dāng)連接不正常,則斷開連接;然后判斷從上次通信時間到當(dāng)前時間是否已經(jīng)超過下線超時時間,或者本節(jié)點自身激勵的角色和其他節(jié)點上報的角色不同,當(dāng)滿足以上條件的話,則判定當(dāng)前節(jié)點主觀下線,并發(fā)送主觀下線消息通知訂閱了__sentinel__:hello消息的節(jié)點,讓他們?nèi)ジ伦陨砭S護的信息;實現(xiàn)在方法sentinelCheckSubjectivelyDown中;
? ? 如果當(dāng)前檢測的節(jié)點是主節(jié)點,則需要進行接下來的客觀下線判斷故障轉(zhuǎn)移;
? ? 客觀下線判斷邏輯為:當(dāng)前被檢測節(jié)點如果被判斷為主觀下線,則遍歷所有的監(jiān)視被檢測節(jié)點的的sentinel實例,統(tǒng)計判定被檢測節(jié)點為下線的sentinel實例個數(shù),如果sentinel實例個數(shù)大于配置的客觀下線條件成立的數(shù)量,則判定該節(jié)點客觀下線,并發(fā)送通知給其他sentinel實例。該方法是現(xiàn)在函數(shù)sentinelCheckObjectivelyDown中;
? ? 由于sentinel實例判定某一個被檢測的主節(jié)點同時出于主動下線和被動下線狀態(tài),所以需要進行故障轉(zhuǎn)移;
? ? 1、在某些環(huán)境下使用sentinel部署redis集群,為了保證集群的高可用,可能會同時部署多個sentinel實例,所以首先需要在這些sentinel實例中選舉出進行故障轉(zhuǎn)移的sentinel實例;首先遍歷所有的監(jiān)控被檢測節(jié)點的sentinel實例(sentinelGetLeader方法),統(tǒng)計各個sentinel實例選舉的執(zhí)行故障轉(zhuǎn)移sentinel實例,然后根據(jù)選舉的結(jié)果,獲取執(zhí)行故障轉(zhuǎn)移的sentinel實例的名稱。如果選舉出的實例是不是當(dāng)前sentinel本身,則當(dāng)前sentinel實例直接退出;否則執(zhí)行下一步,并發(fā)送通知,高數(shù)各個訂閱了消息的節(jié)點,sentinel實例正在選擇主節(jié)點;
? ? 2、在當(dāng)前的被檢測的下線的master節(jié)點中,遍歷從屬于該master節(jié)點的所有slave節(jié)點,排除所有的下線節(jié)點、ping命令超時節(jié)點、與sentinel節(jié)點連接斷開的slave節(jié)點、優(yōu)先級為0的節(jié)點、info命令響應(yīng)時間過長的節(jié)點以及復(fù)制拷貝超時過長的slave節(jié)點,然后從剩余的節(jié)點中,按照優(yōu)先級、復(fù)制主程序數(shù)據(jù)量、runid等信息一次排序,選舉出最優(yōu)的slave節(jié)點,將其選做新的master節(jié)點。
? ? 3、接下來就是sentinel節(jié)點發(fā)送通知給其他的節(jié)點,將slave設(shè)置成新的master節(jié)點
到此,整個sentinel的處理流程已經(jīng)介紹完成,部分具體細節(jié),可以查看源碼了解