作者:Wen Hui
轉(zhuǎn)載:中間件小哥
Sentinel 使用和Redis服務(wù)器相同的事件處理機(jī)制:分為文件事件和時(shí)間事件吉捶。文件事件處理機(jī)制使用I/O 多路復(fù)用來處理服務(wù)器端的網(wǎng)絡(luò)I/O 請求翅阵,例如客戶端連接,讀寫等操作赚抡。時(shí)間處理機(jī)制則在主循環(huán)中周期性調(diào)用時(shí)間函數(shù)來處理定時(shí)操作,例如服務(wù)器端的維護(hù)纠屋,定時(shí)更新涂臣,刪除等操作。Redis服務(wù)器主時(shí)間函數(shù)是在server.c中定義的serverCron函數(shù),在默認(rèn)情況下售担,serverCron會(huì)每100ms被調(diào)用一次赁遗。在這個(gè)函數(shù)中,我們看到如下代碼:
其中當(dāng)服務(wù)器以sentinel模式運(yùn)行的時(shí)候族铆,serverCron會(huì)調(diào)用sentinelTimer函數(shù)岩四,來運(yùn)行Sentinel中的主邏輯,sentinelTimer函數(shù)在sentinel.c中的定義如下:
Sentinel Timer函數(shù)會(huì)做如下幾個(gè)操作:
1. 檢查Sentinel當(dāng)前是否在Tilt 模式(Tilt模式將會(huì)在稍后章節(jié)介紹)哥攘。
2. 檢查Sentinel與其監(jiān)控主備實(shí)例剖煌,以及其他Sentinel實(shí)例的連接,更新當(dāng)前狀態(tài)逝淹,并在主實(shí)例下線的時(shí)候自動(dòng)做主備倒換操作耕姊。
3. 檢查回調(diào)腳本狀態(tài),并做相應(yīng)操作栅葡。
4. 更新服務(wù)器頻率(調(diào)用serverCron函數(shù)的頻率)茉兰,加上一個(gè)隨機(jī)因子,作用是防止監(jiān)控相同主節(jié)點(diǎn)的Sentinel在選舉Leader的時(shí)候時(shí)間沖突欣簇,導(dǎo)致選舉無法產(chǎn)生絕對(duì)多的票數(shù)规脸。
其中SentinelHandleDictOfRedisInstances函數(shù)的定義如下:
SentinelHandleDictOfRedisInstances函數(shù)主要做的工作是:
1.調(diào)用sentinelHandleDictOfRedisInstance函數(shù)處理Sentinel與其它特定實(shí)例連接坯约,狀態(tài)更 新,以及主備倒換工作燃辖。
2. 如果當(dāng)前處理實(shí)例為主實(shí)例鬼店,遞歸調(diào)用SentinelHandleDictOfRedisInstances函數(shù)處理其下屬的從實(shí)例以及其他監(jiān)控這個(gè)主實(shí)例的Sentinel。
3. 在主備倒換成功的情況下黔龟,更新主實(shí)例為升級(jí)為主實(shí)例的從實(shí)例妇智。
其中在sentinelHandleRedisInstance的定義如下:
這個(gè)函數(shù)會(huì)做以下兩部分操作:
1. 檢查Sentinel和其他實(shí)例(主備實(shí)例以及其他Sentinel)的連接,如果連接沒有設(shè)置或已經(jīng)斷開連接氏身,Sentinel會(huì)重試相對(duì)應(yīng)的連接巍棱,并定時(shí)發(fā)送響應(yīng)命令。 需要注意的是:Sentinel和每個(gè)主備實(shí)例都有兩個(gè)連接蛋欣,命令連接和發(fā)布訂閱連接航徙。但是與其他監(jiān)聽相同主備實(shí)例的Sentinel只保留命令連接,這部分細(xì)節(jié)會(huì)在網(wǎng)絡(luò)章節(jié)單獨(dú)介紹陷虎。
2. 第二部分操作主要做的是監(jiān)測主備及其他Sentinel實(shí)例到踏,并監(jiān)測其是否在主觀下線狀態(tài),對(duì)于主實(shí)例來說尚猿,還要檢測是否在客觀下線狀態(tài)窝稿,并進(jìn)行相應(yīng)的主備倒換操作。
需要注意的是第二部分操作如果Sentinel在Tilt模式下是忽略的凿掂,下面我們來看一下這個(gè)函數(shù)第二部分的的具體實(shí)現(xiàn)細(xì)節(jié)伴榔。
sentinelCheckSubjectivelyDown 函數(shù)會(huì)監(jiān)測特定的Redis實(shí)例(主備實(shí)例以及其他Sentinel)是否處于主觀下線狀態(tài),這部分函數(shù)代碼如下:
主觀下線狀態(tài)意味著特定的Redis實(shí)例滿足以下條件之一:
1. 在實(shí)例配置的down_after_milliseconds時(shí)間內(nèi)沒有收到Ping的回復(fù)庄萎。
2. Sentinel認(rèn)為實(shí)例是主實(shí)例踪少,但收到實(shí)例為從實(shí)例的回復(fù),并且上次實(shí)例角色回復(fù)時(shí)間大于在實(shí)例配置的down_after_millisecon時(shí)間加上2倍INFO命令間隔糠涛。
如果任何一個(gè)條件滿足援奢,Sentinel會(huì)打開實(shí)例的S_DOWN標(biāo)志并認(rèn)為實(shí)例進(jìn)入主觀下線狀態(tài)。
主觀下線狀態(tài)意味著Sentinel主觀認(rèn)為實(shí)例下線忍捡,但此時(shí)Sentinel并沒有詢問其他監(jiān)控此實(shí)例的其他Sentinel此實(shí)例的在線狀態(tài)集漾。
sentinelCheckObjectivelyDown 函數(shù)會(huì)檢查實(shí)例是否為客觀下線狀態(tài),這個(gè)操作僅僅對(duì)主實(shí)例進(jìn)行锉罐。sentinelCheckObjectivelyDown函數(shù)定義如下:
這個(gè)函數(shù)主要進(jìn)行的操作是循環(huán)查看監(jiān)控此主實(shí)例的其他Sentinel SRI_MASTER_DOWN 標(biāo)志是否打開帆竹,如果打開則意味著其他特定的Sentinel認(rèn)為主實(shí)例處于下線狀態(tài)绕娘,并統(tǒng)計(jì)認(rèn)為主實(shí)例處于下線狀態(tài)的票數(shù)脓规,如果票數(shù)大于等于主實(shí)例配置的quorum值,則Sentinel會(huì)把主實(shí)例的SRI_O_DOWN標(biāo)志打開险领,并認(rèn)為主實(shí)例處于客觀下線狀態(tài)侨舆。
sentinelStartFailoverIfNeeded函數(shù)首先會(huì)檢查實(shí)例是否處于客觀下線狀態(tài)(SRI_O_DOWN標(biāo)志是否打開)秒紧,并且在2倍主實(shí)例配置的主備倒換超時(shí)時(shí)間內(nèi)沒有進(jìn)行主備倒換工作,Sentinel會(huì)打開SRI_FAILOVER_IN_PROGRESS標(biāo)志并設(shè)置倒換狀態(tài)為SENTINEL_FAILOVER_STATE_WAIT_START挨下。并開始進(jìn)行主備倒換工作熔恢。主備倒換的細(xì)節(jié)將在主備倒換的章節(jié)里介紹。
參考資料:
https://github.com/antirez/redis
https://redis.io/topics/sentinel
Redis設(shè)計(jì)與實(shí)現(xiàn)第二版黃健宏著