Sentinel是Redis官方自帶的工具,中文意思是哨兵,顧名思義,就是守衛(wèi)Redis的好幫手。NCR(網(wǎng)易云redis)準(zhǔn)備開(kāi)發(fā)高可用的Redis集群,有計(jì)劃使用Sentinel。本文接下來(lái)介紹下Sentinel的設(shè)計(jì)與實(shí)現(xiàn)。本文介紹的Sentinel是用的2.8.19版本(最新的3.0.0版本Sentinel的功能只比2.8.19多了一個(gè)client命令)。
先引用官方的說(shuō)法介紹下Sentinel的作用。Redis Sentinel是一個(gè)幫助管理Redis實(shí)例的系統(tǒng),它提供以下功能:
- 監(jiān)控(Monitoring):Sentinel會(huì)不斷的檢查你的主節(jié)點(diǎn)和從節(jié)點(diǎn)是否正常工作。
- 通知(Notification):被監(jiān)控的Redis實(shí)例如果出現(xiàn)問(wèn)題,Sentinel可以通過(guò)API(pub)通知系統(tǒng)管理員或者其他程序。
- 自動(dòng)故障轉(zhuǎn)移(Automatic failover):如果一個(gè)master離線,Sentinel會(huì)開(kāi)始進(jìn)行故障轉(zhuǎn)移,master下的一個(gè)slave會(huì)被選為新的master,其他的slave會(huì)開(kāi)始復(fù)制新的master。應(yīng)用可以通過(guò)Redis服務(wù)的通知機(jī)制更新新的master地址。
- 配置提供者(Configuration provider):客戶端可以把Sentinel作為權(quán)威的配置發(fā)布者來(lái)獲得最新的master地址。如果發(fā)生了故障轉(zhuǎn)移,Sentinel集群會(huì)通知客戶端新的master地址。
Sentinel是如何運(yùn)行的?又是如何提供對(duì)Redis的監(jiān)控和故障轉(zhuǎn)移呢?
特殊狀態(tài)的Redis
一個(gè)Sentinel就是一個(gè)運(yùn)行在特殊狀態(tài)下的Redis,以至于可以用啟動(dòng)Redis Server的方式啟動(dòng)Sentinel。不過(guò)Sentinel有自己的命令列表,它支持的命令不多。
struct redisCommand sentinelcmds[] = { {"ping",pingCommand,1,"",0,NULL,0,0,0,0,0}, {"sentinel",sentinelCommand,-2,"",0,NULL,0,0,0,0,0}, {"subscribe",subscribeCommand,-2,"",0,NULL,0,0,0,0,0}, {"unsubscribe",unsubscribeCommand,-1,"",0,NULL,0,0,0,0,0}, {"psubscribe",psubscribeCommand,-2,"",0,NULL,0,0,0,0,0}, {"punsubscribe",punsubscribeCommand,-1,"",0,NULL,0,0,0,0,0}, {"publish",sentinelPublishCommand,3,"",0,NULL,0,0,0,0,0}, {"info",sentinelInfoCommand,-1,"",0,NULL,0,0,0,0,0}, {"role",sentinelRoleCommand,1,"l",0,NULL,0,0,0,0,0}, {"shutdown",shutdownCommand,-1,"",0,NULL,0,0,0,0,0} };
上面就是Sentinel支持的所有命令了。后面會(huì)對(duì)這些命令進(jìn)行詳細(xì)的說(shuō)明。
配置Redis主節(jié)點(diǎn),自動(dòng)發(fā)現(xiàn)從節(jié)點(diǎn)
Sentinel運(yùn)行起來(lái)后,會(huì)根據(jù)配置文件的"sentinel monitor <master-name> <ip> <redis-port> <quorum>"
去連接master,這里我們把master-name下的所有節(jié)點(diǎn)看成一個(gè)group,一個(gè)group由一個(gè)master,若干個(gè)slave組成。Sentinel只需配置主節(jié)點(diǎn)的ip、port即可。Sentinel會(huì)通過(guò)向master發(fā)送INFO命令來(lái)獲取master下的slave,然后把slave加入group。
自動(dòng)發(fā)現(xiàn)監(jiān)控同一個(gè)group的其他Sentinel
Sentinel連接Redis節(jié)點(diǎn),會(huì)創(chuàng)建兩條對(duì)節(jié)點(diǎn)的連接,一條用來(lái)向節(jié)點(diǎn)發(fā)送命令,另一條用來(lái)訂閱“__sentinel__:hello”
頻道(hello頻道)發(fā)來(lái)的消息,這個(gè)頻道用做Gossip協(xié)議發(fā)現(xiàn)其他監(jiān)控此Redis節(jié)點(diǎn)的Sentinel。每個(gè)Sentinel會(huì)定時(shí)向頻道發(fā)送消息,然后也會(huì)接收到其他Sentinel從hello頻道發(fā)來(lái)的消息,消息的格式如下:sentinel_ip,sentinel_port,sentinel_runid,current_epoch,master_name,master_ip,master_port,master_config_epoch
(127.0.0.1,26381,99ce8dc79e55ce9de040b0cd13d152900db9a7e1,24,mymaster2,127.0.0.1,8000,0)。
這樣監(jiān)控同一個(gè)group的的Sentinel就組成了一個(gè)集群,每個(gè)Sentinel會(huì)創(chuàng)建一條連向其他Sentinel的連接,這是在做自動(dòng)故障轉(zhuǎn)移的時(shí)候可以像其他節(jié)點(diǎn)發(fā)送命令。
推送消息
Sentinel在監(jiān)控Redis和其他Sentinel的時(shí)候,發(fā)現(xiàn)的異常以及完成的操作都會(huì)通過(guò)Publish的方式推送出去,客戶端想了解Sentinel的處理結(jié)果,只要訂閱相應(yīng)的消息類型即可。Sentinel使用的推送方式用的是Redis現(xiàn)有的Pub/Sub方式。Sentinel基本上會(huì)把它整個(gè)處理流程都推送出來(lái),然而客戶端一般只要關(guān)注主從切換的消息即可。
故障檢查
Sentinel會(huì)跟group的每個(gè)節(jié)點(diǎn)以及監(jiān)控同一個(gè)group的其他Sentinel保持心跳,Sentinel會(huì)定時(shí)向這些節(jié)點(diǎn)發(fā)送Ping命令,然后等待Pong命令回復(fù)。如果一段時(shí)間沒(méi)有收到Pong命令。Sentinel就會(huì)主觀的認(rèn)為該節(jié)點(diǎn)離線。對(duì)于其他Sentinel和group內(nèi)的slave掛了,Sentinel檢測(cè)到他們離線也不需要做什么事情,只是簡(jiǎn)單的推送一條+sdown
的消息。如果檢測(cè)到master離線,Sentinel就要確定是否需要進(jìn)行主從切換。此時(shí)Sentinel會(huì)向其他Sentinel發(fā)送is-master-down-by-addr
命令(命令格式:SENTINEL IS-master-DOWN-BY-ADDR <ip> <port> <current-epoch> <runid>
),這個(gè)命令有2個(gè)功能,這時(shí)候的用法是用來(lái)向其他節(jié)點(diǎn)獲取master是否離線的信息。還有一個(gè)用法是用來(lái)選舉leader的,該命令會(huì)讓其他Sentinel給自己投票,已經(jīng)投過(guò)票的Sentinel會(huì)返回投票的結(jié)果。Sentinel在監(jiān)控group的時(shí)候會(huì)配置一個(gè)quorum,Sentinel接收到超過(guò)quorum個(gè)Sentinel認(rèn)為master掛了(quorum包含自己),Sentinel就會(huì)認(rèn)為該master是客觀下線了。接著Sentinel就進(jìn)入了自動(dòng)故障轉(zhuǎn)移狀態(tài)。
Sentinel間投票選leader
Sentinel認(rèn)為master客觀下線了,就開(kāi)始故障轉(zhuǎn)移流程,故障轉(zhuǎn)移的第一步就是競(jìng)選leaderSentinel采用了Raft協(xié)議實(shí)現(xiàn)了Sentinel間選舉Leader的算法,不過(guò)也不完全跟論文描述的步驟一致。Sentinel集群運(yùn)行過(guò)程中故障轉(zhuǎn)移完成,所有Sentinel又會(huì)恢復(fù)平等。Leader僅僅是故障轉(zhuǎn)移操作出現(xiàn)的角色。
選舉流程
Sentinel采用了Raft協(xié)議實(shí)現(xiàn)了Sentinel間選舉Leader的算法,不過(guò)也不完全跟論文描述的步驟一致。
- 1、某個(gè)Sentinel認(rèn)定master客觀下線的節(jié)點(diǎn)后,該Sentinel會(huì)先看看自己有沒(méi)有投過(guò)票,如果自己已經(jīng)投過(guò)票給其他Sentinel了,在2倍故障轉(zhuǎn)移的超時(shí)時(shí)間自己就不會(huì)成為L(zhǎng)eader。相當(dāng)于它是一個(gè)Follower。
- 2、如果該Sentinel還沒(méi)投過(guò)票,那么它就成為Candidate。
- 3、和Raft協(xié)議描述的一樣,成為Candidate,Sentinel需要完成幾件事情
- 1)更新故障轉(zhuǎn)移狀態(tài)為start
- 2)當(dāng)前epoch加1,相當(dāng)于進(jìn)入一個(gè)新term,在Sentinel中epoch就是Raft協(xié)議中的term。
- 3)更新自己的超時(shí)時(shí)間為當(dāng)前時(shí)間隨機(jī)加上一段時(shí)間,隨機(jī)時(shí)間為1s內(nèi)的隨機(jī)毫秒數(shù)。
- 4)向其他節(jié)點(diǎn)發(fā)送
is-master-down-by-addr
命令請(qǐng)求投票。命令會(huì)帶上自己的epoch。 - 5)給自己投一票,在Sentinel中,投票的方式是把自己master結(jié)構(gòu)體里的leader和leader_epoch改成投給的Sentinel和它的epoch。
- 4、其他Sentinel會(huì)收到Candidate的
is-master-down-by-addr
命令。如果Sentinel當(dāng)前epoch和Candidate傳給他的epoch一樣,說(shuō)明他已經(jīng)把自己master結(jié)構(gòu)體里的leader和leader_epoch改成其他Candidate,相當(dāng)于把票投給了其他Candidate。投過(guò)票給別的Sentinel后,在當(dāng)前epoch內(nèi)自己就只能成為Follower。 - 5、Candidate會(huì)不斷的統(tǒng)計(jì)自己的票數(shù),直到他發(fā)現(xiàn)認(rèn)同他成為L(zhǎng)eader的票數(shù)超過(guò)一半而且超過(guò)它配置的quorum(quorum可以參考《redis sentinel(哨兵) 設(shè)計(jì)與實(shí)現(xiàn)》)。Sentinel比Raft協(xié)議增加了quorum,這樣一個(gè)Sentinel能否當(dāng)選Leader還取決于它配置的quorum。
- 6、如果在一個(gè)選舉時(shí)間內(nèi),Candidate沒(méi)有獲得超過(guò)一半且超過(guò)它配置的quorum的票數(shù),自己的這次選舉就失敗了。
- 7、如果在一個(gè)epoch內(nèi),沒(méi)有一個(gè)Candidate獲得更多的票數(shù)。那么等待超過(guò)2倍故障轉(zhuǎn)移的超時(shí)時(shí)間后,Candidate增加epoch重新投票。
- 8、如果某個(gè)Candidate獲得超過(guò)一半且超過(guò)它配置的quorum的票數(shù),那么它就成為了Leader。
- 9、與Raft協(xié)議不同,Leader并不會(huì)把自己成為L(zhǎng)eader的消息發(fā)給其他Sentinel。其他Sentinel等待Leader從slave選出master后,檢測(cè)到新的master正常工作后,就會(huì)去掉客觀下線的標(biāo)識(shí),從而不需要進(jìn)入故障轉(zhuǎn)移流程。
關(guān)于Sentinel超時(shí)時(shí)間的說(shuō)明
Sentinel超時(shí)機(jī)制并不像Raft協(xié)議描述的那樣只使用了一個(gè)隨機(jī)超時(shí)機(jī)制。它有幾個(gè)超時(shí)概念。
- failover_start_time 下一選舉啟動(dòng)的時(shí)間。默認(rèn)是當(dāng)前時(shí)間加上1s內(nèi)的隨機(jī)毫秒數(shù)
- failover_state_change_time 故障轉(zhuǎn)移中狀態(tài)變更的時(shí)間。
- failover_timeout 故障轉(zhuǎn)移超時(shí)時(shí)間。默認(rèn)是3分鐘。
- election_timeout 選舉超時(shí)時(shí)間,是默認(rèn)選舉超時(shí)時(shí)間和failover_timeout的最小值。默認(rèn)是10s。
Follower成為Candidate后,會(huì)更新failover_start_time為當(dāng)前時(shí)間加上1s內(nèi)的隨機(jī)毫秒數(shù)。更新failover_state_change_time為當(dāng)前時(shí)間。
Candidate的當(dāng)前時(shí)間減去failover_start_time大于election_timeout,說(shuō)明Candidate還沒(méi)獲得足夠的選票,此次epoch的選舉已經(jīng)超時(shí),那么轉(zhuǎn)變成Follower。需要等到mstime() - failover_start_time < failover_timeout*2
的時(shí)候才開(kāi)始下一次獲得成為Candidate的機(jī)會(huì)。
如果一個(gè)Follower把某個(gè)Candidate設(shè)為自己認(rèn)為的Leader,那么它的failover_start_time會(huì)設(shè)置為當(dāng)前時(shí)間加上1s內(nèi)的隨機(jī)毫秒數(shù)。這樣它就進(jìn)入了上面說(shuō)的需要等到mstime() - failover_start_time < failover_timeout*2
的時(shí)候才開(kāi)始下一次獲得成為Candidate的機(jī)會(huì)。
因?yàn)槊總€(gè)Sentinel判斷節(jié)點(diǎn)客觀下線的時(shí)間不是同時(shí)開(kāi)始的,一般都有先后,這樣先開(kāi)始的Sentinel就更有機(jī)會(huì)贏得更多選票,另外failover_state_change_time為1s內(nèi)的隨機(jī)毫秒數(shù),這樣也把各個(gè)節(jié)點(diǎn)的超時(shí)時(shí)間分散開(kāi)來(lái)。本人嘗試過(guò)很多次,Sentinel間的Leader選舉過(guò)程基本上一個(gè)epoch內(nèi)就完成了。
故障轉(zhuǎn)移
Sentinel一旦確定自己是leader后,就開(kāi)始從slave中選出一個(gè)節(jié)點(diǎn)來(lái)作為master。以下是選擇slave的流程:
- 1、過(guò)濾掉slave列表中主觀、客觀下線和離線的slave。
- 2、過(guò)濾掉slave列表中5s沒(méi)響應(yīng)ping的slave。
- 3、過(guò)濾掉slave列表中優(yōu)先級(jí)為0的slave。(slave的優(yōu)先級(jí)是redis的配置參數(shù)slave-priority,默認(rèn)是100)
- 3、過(guò)濾掉slave列表中一段時(shí)間沒(méi)有回復(fù)INFO的slave。
- 4、過(guò)濾掉slave列表中很久沒(méi)跟master連接的slave。
- 5、比較篩選后的slave,優(yōu)先級(jí)小的slave被選為新master。
- 6、如果優(yōu)先級(jí)相同,比較slave對(duì)原master的復(fù)制偏移量,偏移量大的slave被選為新master。
- 7、如果復(fù)制偏移量相同,那就直接比較slave的運(yùn)行id,字符串小的slave被選為新master。
如果依據(jù)選擇流程沒(méi)有選出可用的slave,leader Sentinel會(huì)終止本次故障轉(zhuǎn)移。
如果選擇除了可用的slave,那么leader Sentinel會(huì)給該slave發(fā)送slaveof no one
命令,表示該slave不再?gòu)?fù)制其他節(jié)點(diǎn),成為了master。然后leader Sentinel就會(huì)一直等待選出slave的INFO信息里面確認(rèn)了自己的master身份。如果等待超時(shí)了,leader Sentinel只得終止本次故障轉(zhuǎn)移。
如果選出的slave確認(rèn)了自己的master身份,leader Sentinel會(huì)讓其他slave復(fù)制新的master,由于初次復(fù)制會(huì)帶來(lái)很大的IO開(kāi)銷,Sentinel有個(gè)parallel_syncs
參數(shù),用來(lái)確定一次讓多少個(gè)slave復(fù)制新master。一個(gè)slave復(fù)制master如果超過(guò)10s,leader Sentinel會(huì)重新發(fā)送復(fù)制命令。如果在指定的故障轉(zhuǎn)移時(shí)間內(nèi)還沒(méi)有完成全部的復(fù)制工作,leader Sentinel就會(huì)忽略那些沒(méi)復(fù)制的slave。leader Sentinel只是向這些slave發(fā)送一次復(fù)制命令,不等待他們復(fù)制成功就直接完成了全部故障轉(zhuǎn)移工作。
全部故障轉(zhuǎn)移工作完成后,leader Sentinel就會(huì)推送+switch-master
消息,同時(shí)重置master,重置操作會(huì)釋放掉原來(lái)master全部的slave對(duì)象和監(jiān)聽(tīng)該master的其他Sentinel對(duì)象,然后創(chuàng)建出新的slave對(duì)象。
TILT保護(hù)模式
TILT模式是Sentinel發(fā)現(xiàn)進(jìn)程出現(xiàn)異常時(shí)候的一種保護(hù)模式。Sentinel定時(shí)器默認(rèn)每100ms執(zhí)行一次,Sentinel每次啟動(dòng)定時(shí)任務(wù)的時(shí)候會(huì)檢查下上次定時(shí)任務(wù)執(zhí)行的時(shí)間,如果超過(guò)2s或者小于0了,Sentinel就認(rèn)為操作系統(tǒng)出現(xiàn)異常,導(dǎo)致一次任務(wù)的執(zhí)行時(shí)間過(guò)長(zhǎng),就會(huì)進(jìn)入TILT模式。TILT模式下,Sentinel不再執(zhí)行任何操作。其他Sentinel發(fā)送的SENTINEL is-master-down-by-addr
命令會(huì)直接返回負(fù)值。
如果TILT模式下的Sentinel正常運(yùn)行超過(guò)30s,Sentinel就會(huì)解除TILT模式。
客戶端處理流程
客戶端可以通過(guò)Sentinel獲得group的信息。官方給出了客戶端操作的推薦方式。看了下Jedis的實(shí)現(xiàn),基本就是按照官方的操作流程進(jìn)行的。首先客戶端配置監(jiān)聽(tīng)該group的全部Sentinel。連接第一個(gè)Sentinel,如果連不上就重新連接下一個(gè),直到連上一個(gè)Sentinel。
連上Sentinel后,發(fā)送SENTINEL get-master-addr-by-name master-name
命令可以得到該group的master,如果該Sentinel返回了null,那就重復(fù)上面的流程,重新連接下一個(gè)Sentinel。
得到group的master后,連上master,發(fā)送ROLE命令,確認(rèn)該master自身確實(shí)是作為master在運(yùn)行。這個(gè)確認(rèn)是必須的,如果Sentinel和group網(wǎng)絡(luò)分區(qū)了,那么該Sentinel認(rèn)為的master就不會(huì)變化了,而group如果出現(xiàn)主從切換,此時(shí)Sentinel就拿不到真實(shí)的master了。如果ROLE得到的不再是master了,客戶端需要重復(fù)最前面的流程,重新連接下一個(gè)Sentinel。
確認(rèn)好master的ROLE也是master后,客戶端可以從每個(gè)Sentinel上訂閱消息。一般客戶端只要關(guān)心+switch-master
即可,這個(gè)消息會(huì)告訴客戶端發(fā)生了主從切換,并把新老master的ip、port都推送在消息里。客戶端根據(jù)新的master,發(fā)送ROLE命令確認(rèn)后,就可以和新的master通信了。
有些客戶端希望把讀流量分給slave,那么可以通過(guò)SENTINEL slaves master-name
命令來(lái)獲得該group下的slave列表。
如果客戶端需要重連master,那么建議按照初始化連接的方式重新從Sentinel獲取master。
如果采用連接池的方式,官方建議在每次有連接斷開(kāi)需要重連的時(shí)候所有的連接都關(guān)閉,從而重建連接池。這么做也是為了防止新的連接獲取的master跟原來(lái)不一致了。
客戶端還可以通過(guò)SENTINEL sentinels <master-name>
命令更新自己的Sentinel列表,從而獲得最新存活的Sentinel。
狀態(tài)持久化
Sentinel的狀態(tài)會(huì)持久化到配置文件。例如每一次通過(guò)set命令設(shè)置新的配置,或者加入新節(jié)點(diǎn)的監(jiān)控,修改的配置會(huì)持久化到配置文件,同時(shí)持久化配置的epoch,這意味著停止和重啟Sentinel是安全的。
分區(qū)問(wèn)題
Sentinel集群會(huì)有分區(qū)問(wèn)題,這個(gè)在官方文檔上有說(shuō)明。
在該圖中,Redis 3原來(lái)是master,網(wǎng)絡(luò)分區(qū)后,Sentinel1和Sentinel2會(huì)把Redis 1選舉為master。此時(shí)問(wèn)題出現(xiàn)了,由于Sentinel3和Redis3處于另外分區(qū),所以Sentinel3依然認(rèn)為Redis3是master,此時(shí)處于分區(qū)內(nèi)的Client B從Sentinel3獲得的master就是Redis3,而Redis3也認(rèn)為自己是Redis3,客戶端依然能夠操作group,此時(shí)Client A和Client B操作的master已經(jīng)不一樣了,同一個(gè)group出現(xiàn)了不一致現(xiàn)象。Redis官方給出了兩個(gè)建議。
等分區(qū)恢復(fù)后,Client B在Redis3上的寫(xiě)數(shù)據(jù)會(huì)丟失,如果你把Redis當(dāng)做緩存,能夠接受這種現(xiàn)象,那么可以忽略這個(gè)問(wèn)題。
如果不想忽略這個(gè)問(wèn)題,那么對(duì)于redis可以這樣配置
min-slaves-to-write 1 min-slaves-max-lag 10
min-slaves-to-write
設(shè)置為1,保證了master認(rèn)為至少有一個(gè)slave連接正常,master才能正常工作,上面Redis3因?yàn)橐呀?jīng)與原來(lái)的兩個(gè)slave無(wú)法連接,所以Redis3此時(shí)已經(jīng)無(wú)效了。(min-slaves-max-lag
是主從ack延遲的最大時(shí)間。單位是秒)
連接爆炸
Sentinel還有個(gè)連接爆炸的問(wèn)題。Sentinel的所有操作都是基于group進(jìn)行的,不同group之間流程完全不干擾,Sentinel會(huì)去發(fā)現(xiàn)監(jiān)控相同group的其他Sentinel,即使一個(gè)在其他group的Sentinel已經(jīng)和本Sentinel建立了連接,在這個(gè)group內(nèi),也仍然會(huì)繼續(xù)建立連接,同時(shí)從這個(gè)連接發(fā)送ping命令確定其他Sentinel的存活,這個(gè)帶來(lái)的好處是流程簡(jiǎn)潔,代碼清晰。但缺點(diǎn)就是帶來(lái)了連接數(shù)的消耗和大量的重復(fù)消息。下面我們從代碼的層面看下出現(xiàn)連接爆炸的原因。整個(gè)Sentinel主要就使用了兩個(gè)結(jié)構(gòu)體。一個(gè)是sentinelState,用來(lái)記錄Sentinel的全局狀態(tài)。另一個(gè)是sentinelRedisInstance,用來(lái)記錄Sentinel監(jiān)控的每一個(gè)節(jié)點(diǎn)的信息。sentinelState有一個(gè)記錄所有g(shù)roup的hash表,dict *masters
。masters記錄了所有主節(jié)點(diǎn)的信息,hash表的鍵是主節(jié)點(diǎn)的名稱,值是一個(gè)sentinelRedisInstance結(jié)構(gòu)。
struct sentinelState { ... dict *masters; /* Dictionary of master sentinelRedisInstances. Key is the instance name, value is the sentinelRedisInstance structure pointer. */ ... } sentinel;
sentinelRedisInstance結(jié)構(gòu)里面記錄了整個(gè)group的詳細(xì)信息,其中包括slave的hash表和sentinel的hash表。
typedef struct sentinelRedisInstance { ... dict *sentinels; /* Other sentinels monitoring the same master. */ dict *slaves; /* slaves for this master instance. */ ... } sentinelRedisInstance;
dict *sentinels
記錄了監(jiān)控該group除自己外的其他Sentinel。問(wèn)題就出在這里。前面介紹了Sentinel發(fā)現(xiàn)其他Sentinel是通過(guò)訂閱hello頻道的消息。Sentinel會(huì)訂閱每個(gè)group的消息,然后當(dāng)在一個(gè)group的hello頻道發(fā)現(xiàn)一個(gè)新的Sentinel后,Sentinel會(huì)為這個(gè)Sentinel生成一個(gè)新的sentinelRedisInstance結(jié)構(gòu),加入該group的sentinels的hash表里面。每次生成新的sentinelRedisInstance結(jié)構(gòu),都是從內(nèi)存重新分配數(shù)據(jù),重新和Sentinel建立連接。這樣如果另外也有一個(gè)Sentinel和自己監(jiān)聽(tīng)了相同group列表的話,他們會(huì)針對(duì)每個(gè)group彼此都建立一條連接。隨著Sentinel監(jiān)聽(tīng)的group針對(duì),連接將成倍數(shù)的增加!這里還沒(méi)結(jié)束。Sentinel有個(gè)輪詢線程會(huì)監(jiān)聽(tīng)每個(gè)節(jié)點(diǎn)的狀態(tài)。這樣,對(duì)另一個(gè)Sentinel,本Sentinel會(huì)對(duì)每個(gè)group上建立的連接向另一個(gè)Sentinel發(fā)送Ping命令,從而產(chǎn)生了大量的重復(fù)消息。
Sentinel命令列表
以下對(duì)Sentinel的每個(gè)命令做個(gè)說(shuō)明。
* ping 用來(lái)探測(cè)節(jié)點(diǎn)的存活,正常會(huì)返回pong。 * sentinel 下面也很多子命令 masters(SENTINEL masterS) 獲得Sentinel監(jiān)控的所有master信息 master (SENTINEL master <name>) 獲得某個(gè)master信息 slaves (SENTINEL slaveS <master-name>) 獲得某個(gè)master信息 sentinels (SENTINEL SENTINELS <master-name>) 獲得監(jiān)控同一個(gè)group的其他sentinel信息 is-master-down-by-addr (SENTINEL IS-master-DOWN-BY-ADDR <ip> <port> <current-epoch> <runid>*/ 獲得該Sentinel對(duì)于某個(gè)master存活狀態(tài),同時(shí)讓該Sentinel為自己投票 reset (SENTINEL RESET <pattern>) 重置指定pattern的group信息 get-master-addr-by-name (SENTINEL GET-master-ADDR-BY-NAME <master-name>) 獲得某個(gè)group下master信息 failover (SENTINEL FAILOVER <master-name>) 主動(dòng)觸發(fā)一次故障轉(zhuǎn)移 pending-scripts (SENTINEL PENDING-SCRIPTS) 執(zhí)行腳本 monitor (SENTINEL MONITOR <name> <ip> <port> <quorum>) 開(kāi)始監(jiān)控某個(gè)group remove (SENTINEL REMOVE <name>) 移除對(duì)該group的監(jiān)控 set (SENTINEL SET <mastername> [<option> <value> ...]) sentinel動(dòng)態(tài)設(shè)置Sentinel配置命令 down-after-milliseconds (down-after-millisecodns <milliseconds>) 設(shè)置該<mastername> ping多長(zhǎng)時(shí)間未響應(yīng)才判定為離線,默認(rèn)是30s failover-timeout (failover-timeout <milliseconds>) 故障轉(zhuǎn)移的超時(shí)時(shí)間,默認(rèn)是180s parallel-syncs (parallel-syncs <milliseconds>) 同時(shí)讓多少個(gè)slave復(fù)制新的master,默認(rèn)是1 notification-script (notification-script <path>) 用于通知管理員的腳本的地址 client-reconfig-script (client-reconfig-script <path>) 需要執(zhí)行的腳本的地址 auth-pass (auth-pass <password>) group的master密碼 quorum (quorum <count>) 用于配置多少個(gè)Sentinel認(rèn)為節(jié)點(diǎn)下線才認(rèn)為客觀下線的數(shù)量。 * subscribe 訂閱某個(gè)頻道 * unsubscribe 退訂某個(gè)頻道 * psubscribe 訂閱某個(gè)模式,可以批量訂閱一些頻道 * punsubscribe 退訂某個(gè)模式 * publish 發(fā)布消息,用作測(cè)試。只能發(fā)布hello頻道的消息 * info 查看Sentinel信息。 * role 查看Sentinel和負(fù)責(zé)監(jiān)控的master列表。 * shutdown 關(guān)閉Sentinel
推送的消息內(nèi)容
以下是Sentinel推送的所有消息。從Sentinel的推送消息,基本上可以看到Sentinel運(yùn)行的整個(gè)流程。
- +monitor
quorum 有新的master被監(jiān)控。 - +reset-master
master器已被重置。 - +slave
一個(gè)新的slave已經(jīng)被Sentinel檢測(cè)到并關(guān)聯(lián)到對(duì)應(yīng)的master。 - -pubsub-link
訂閱連接斷線。 - -cmd-link
命令連接斷開(kāi)。 - +pubsub-link
推送訂閱連接連上的消息。 - +cmd-link
推送命令連接連上的消息。 - -cmd-link-reconnection
命令連接重連出錯(cuò)。 - -pubsub-link-reconnection
訂閱連接重連出錯(cuò)。 - +reboot
節(jié)點(diǎn)重啟,更換了新的runid。 - +role-change
new reported role is 通過(guò)解析info信息發(fā)現(xiàn)role可能有變化,role發(fā)生變化。 - -role-change
new reported role is 通過(guò)解析info信息發(fā)現(xiàn)role可能有變化,role沒(méi)有發(fā)生變化。 - +promoted-slave
故障轉(zhuǎn)移過(guò)測(cè)中,新的master自己確認(rèn)了master的角色。 - +failover-state-reconf-slaves
該消息緊接著+promoted-slave消息,此時(shí)故障轉(zhuǎn)移已經(jīng)進(jìn)入了reconf-slaves狀態(tài)。 - +convert-to-slave
新的master一段時(shí)間沒(méi)有確認(rèn)自己的master角色,而且它原來(lái)的master已經(jīng)運(yùn)行正常了,則重新復(fù)制原來(lái)的master,自己重新做回slave。 - +fix-slave-config
slave現(xiàn)在的master地址和Sentinel保存的master不一致,則讓slave重新復(fù)制Sentinel認(rèn)為的master。 - +slave-reconf-inprog
slave正在復(fù)制master。 - +slave-reconf-done
slave復(fù)制master完成。 * -dup-sentinel #duplicate of : or 通過(guò)hello頻道得到的Sentinel信息與已經(jīng)保存的Sentinel信息產(chǎn)生沖突,需要被移除 —— 當(dāng) Sentinel 實(shí)例重啟的時(shí)候,就會(huì)出現(xiàn)這種情況。 - +sentinel
一個(gè)新的Sentinel已經(jīng)被Sentinel檢測(cè)到并關(guān)聯(lián)到對(duì)應(yīng)的master。 - +new-epoch
當(dāng)前epoch被更新。 - +config-update-from
leader完成故障轉(zhuǎn)移后,其他Sentinel通過(guò)hello頻道獲得新的配置信息。 +switch-master <master-name> <old master ip> <old master port> <new master ip> <new master port>
配置變更,maseter的IP和port已經(jīng)改變。這是絕大多數(shù)外部用戶都關(guān)心的信息。- -monitor
去掉了對(duì)該master的監(jiān)控。 - +set
- +sdown
給定的實(shí)例現(xiàn)在處于主觀下線狀態(tài)。 - -sdown
給定的實(shí)例已經(jīng)不再處于主觀下線狀態(tài)。 - +odown
#quorum / 給定的實(shí)例現(xiàn)在處于客觀下線狀態(tài)。 - -odown
給定的實(shí)例已經(jīng)不再處于客觀下線狀態(tài)。 - +vote-for-leader
把某個(gè)Sentinel設(shè)置為leader。 - +try-failover
嘗試故障遷移操作,等待被大多數(shù)Sentinel選中。 - -failover-abort-not-elected
Sentinel 的當(dāng)選時(shí)間已過(guò),取消故障轉(zhuǎn)移計(jì)劃。 - +elected-leader
贏得指定epoch的選舉,可以進(jìn)行故障遷移操作。 - +failover-state-select-slave
故障轉(zhuǎn)移步驟中開(kāi)始選擇slave - -failover-abort-no-good-slave
Sentinel沒(méi)有找到合適的slave提升為master,一段時(shí)間后將重試,但是也可能在重試的時(shí)候出現(xiàn)相同的找不到合適slave的情況。 - +selected-slave
故障轉(zhuǎn)移中,選出了slave作為新的master。 - +failover-state-send-slaveof-noone
故障轉(zhuǎn)移中,選出了slave作為新的master后準(zhǔn)備把slave提升為master。 - -failover-abort-slave-timeout
slave提升為master超時(shí)。 - +failover-state-wait-promotion
新master執(zhí)行slaveof no one成功。 - +failover-end-for-timeout
故障轉(zhuǎn)移超過(guò)時(shí)間,還有slave沒(méi)有復(fù)制完新的master。 - +failover-end
故障轉(zhuǎn)移順利結(jié)束。 - +slave-reconf-sent-be
故障轉(zhuǎn)移超過(guò)時(shí)間,還有slave沒(méi)有復(fù)制完新的master。這些slave將直接發(fā)送復(fù)制新master命令后就完成了整個(gè)故障轉(zhuǎn)移操作。 - -slave-reconf-sent-timeout
超時(shí)的slave也正常完成復(fù)制工作。 - +slave-reconf-sent
leader Sentinel 向slave發(fā)送了復(fù)制命令,為slave設(shè)置新的master。 - -tilt #tilt mode exited 退出 tilt 模式。
- +tilt #tilt mode entered 進(jìn)入 tilt 模式。
參考資料:
http://redis.io/topics/sentinel
http://redis.io/topics/sentinel-clients
http://redisdoc.com/topic/sentinel.html
http://www.wzxue.com/redis核心解讀-集群管理工具redis-sentinel
《In Search of an Understandable Consensus Algorithm》 Diego Ongaro and John Ousterhout Stanford University
《Redis設(shè)計(jì)與實(shí)現(xiàn)》黃健宏 機(jī)械工業(yè)出版社