在切換中,配置文件是會(huì)被動(dòng)態(tài)修改的,例如當(dāng)發(fā)生主備切換時(shí)候,配置文件中的master會(huì)被修改為另外一個(gè)slave。這樣,之后sentinel如果重啟時(shí),就可以根據(jù)這個(gè)配置來恢復(fù)其之前所監(jiān)控的redis集群的狀態(tài)。 在sentinel切換過程中有三大步驟:
- 判斷是否下線(老主是否真的咽氣駕崩) 每個(gè)sentinel在監(jiān)控的時(shí)候,每秒對(duì)主進(jìn)行一次ping命令,如果多次ping的響應(yīng)時(shí)間超過了配置文件中的down-after-milliseconds,那么這個(gè)哨兵就會(huì)認(rèn)為被監(jiān)控的實(shí)例是SDown狀態(tài)(Subjectively Down,主觀down,SDOWN)。 這個(gè)時(shí)候此sentinel會(huì)判斷此master是否真的掛了——即可以設(shè)置成ODOWN(Objectively Down,客觀down,ODOWN)。設(shè)置成ODOWN的條件是除了當(dāng)前sentinel認(rèn)為此master SDOWN,還必須有其他sentinel認(rèn)為此master SDOWN,當(dāng)認(rèn)為SDOWN的sentinel的個(gè)數(shù)等于或超過配置文件中monitor master最后的那個(gè)參數(shù)quorum后,就sentinel就會(huì)認(rèn)為此master是ODOWN。 被標(biāo)記為ODOWN的另一個(gè)效應(yīng)是:在一般情況下,每個(gè) Sentinel 進(jìn)程會(huì)以每 10 秒一次的頻率向它已知的所有主實(shí)例和從實(shí)例發(fā)送 INFO 命令。 當(dāng)一個(gè)主實(shí)例被 Sentinel實(shí)例標(biāo)記為客觀下線時(shí), Sentinel 向ODOWN Master的所有從實(shí)例發(fā)送 INFO 命令的頻率會(huì)從 10 秒一次改為每秒一次。
- 進(jìn)行投票選舉主持切換的sentinel(選舉一個(gè)長(zhǎng)老,由它來欽點(diǎn)新帝王) 當(dāng)master被認(rèn)為是ODOWN的時(shí)候,可能需要進(jìn)行failover,但是并不是odown了就可以執(zhí)行failover,因?yàn)榭赡苡卸鄠€(gè)sentinel都認(rèn)為master是odown了,這時(shí)候就需要選舉一個(gè)sentiel來執(zhí)行failover。也就是說切換之前要先選舉一個(gè)sentinel來主持切換,條件是必須有>=max(quorum, num(sentinels)/2 +1)的sentinel都同意某一個(gè)sentinel主持failover,那么這個(gè)sentinel就可以主持failover,超過半數(shù)這個(gè)條件就能限制住此時(shí)刻只有一個(gè)sentinel來操作。 這個(gè)也是通過is-master-down-by-addr消息進(jìn)行更新每個(gè)sentinel的選舉的leader。每個(gè)sentinel都有一個(gè)epoch,這個(gè)東西相當(dāng)于一個(gè)時(shí)間戳,是遞增的值,如果集群正常的話,所有的sentinel的這個(gè)值都是一樣的。當(dāng)master出現(xiàn)異常后,每個(gè)sentinel后自增這個(gè)值,如果一直沒有選舉出來leader的話,這個(gè)值會(huì)跟隨這time event的輪詢,每次加一,在設(shè)定的故障遷移超時(shí)時(shí)間的兩倍之后, 重新嘗試當(dāng)選。同時(shí)is-master-down-by-addr會(huì)把這個(gè)值發(fā)送到其他的sentinel,其他的sentinel收到這個(gè)消息后,會(huì)判斷自己的epoch和消息中的epoch,如果自己的epoch小于消息中的epoch,那么其他的sentinel就會(huì)選舉傳遞消息的這個(gè)sentinel。最終會(huì)大部分sentinel都同意一個(gè)較大的epoch的sentinel主持failover。
- 進(jìn)行切換,并其他實(shí)例同步新Master(新帝王登基,其余藩王宣誓效忠新帝王) 這個(gè)主持切換的sentinel選出一個(gè)從redis實(shí)例,并將它升級(jí)為Master。首先是要下面的條件按照如下條件篩選備選node: 1) slave節(jié)點(diǎn)狀態(tài)處于S_DOWN,O_DOWN,DISCONNECTED的除外 2) 最近一次ping應(yīng)答時(shí)間不超過5倍ping的間隔(假如ping的間隔為1秒,則最近一次應(yīng)答延遲不應(yīng)超過5秒,redis sentinel默認(rèn)為1秒) 3) info_refresh應(yīng)答不超過3倍info_refresh的間隔(原理同2,redis sentinel默認(rèn)為10秒) 4) slave節(jié)點(diǎn)與master節(jié)點(diǎn)失去聯(lián)系的時(shí)間不能超過( (now - master->s_down_since_time) + (master->down_after_period * 10))??傮w意思是說,slave節(jié)點(diǎn)與master同步太不及時(shí)的(比如新啟動(dòng)的節(jié)點(diǎn)),不應(yīng)該參與被選舉。 5) Slave priority不等于0(這個(gè)是在配置文件中指定,默認(rèn)配置為100)。
然后再?gòu)膫溥xnode中,按照如下順序選擇新的master 1) 較低的slave_priority(這個(gè)是在配置文件中指定,默認(rèn)配置為100) 2) 較大的replication offset(每個(gè)slave在與master同步后offset自動(dòng)增加) 3) 較小的runid(每個(gè)redis實(shí)例,都會(huì)有一個(gè)runid,通常是一個(gè)40位的隨機(jī)字符串,在redis啟動(dòng)時(shí)設(shè)置,重復(fù)概率非常?。?4) 如果以上條件都不足以區(qū)別出唯一的節(jié)點(diǎn),則會(huì)看哪個(gè)slave節(jié)點(diǎn)處理之前master發(fā)送的command多,就選誰(shuí)。 主持切換的sentinel向被選中的從redis實(shí)例發(fā)送 SLAVEOF NO ONE 命令,讓它轉(zhuǎn)變?yōu)镸aster。然后通過發(fā)布與訂閱功能,將更新后的配置傳播給所有其他 Sentinel,其他 Sentinel 對(duì)它們自己的配置進(jìn)行config-rewrite。隨后sentinel向已下線的Master的從服務(wù)器發(fā)送SLAVEOF命令,讓它們?nèi)?fù)制新Master。
注意:sentinel failover-timeout這個(gè)選項(xiàng)有四個(gè)含義,有必要在此翻譯一下 1) 對(duì)于一個(gè)sentinel選出的同一個(gè)master進(jìn)行再次的failover嘗試所需要的時(shí)間——這個(gè)參數(shù)值的兩倍。 2) 當(dāng)sentinel發(fā)現(xiàn)一個(gè)slave錯(cuò)誤的復(fù)制了一個(gè)錯(cuò)的主時(shí)sentinel會(huì)強(qiáng)迫其復(fù)制正確的主的時(shí)間。 3) 取消一個(gè)已經(jīng)開始但是還沒有引起任何配置改變的failover所需要的時(shí)間。 4) 等待所有slave被重新配置為新主的slave而所需要的最大時(shí)間。注意即使超過了這個(gè)時(shí)間sentinel也會(huì)最終配置slave去同步最新的master
更多建議: