淺談Redis Sentinel
Redis 2.8版本開始提供了新一代Sentinel,即所謂的「Sentinel 2」。其大大增強(qiáng)、保障了Redis的高可用

監(jiān)控主從拓?fù)浣Y(jié)構(gòu)
眾所周知在Sentinel的配置文件中,需要配置被監(jiān)控的Master節(jié)點(diǎn)的地址信息(IP、Port)。這樣當(dāng)一個(gè)Sentinel實(shí)例在被創(chuàng)建、初始化時(shí),即會(huì)建立其與Mater節(jié)點(diǎn)的網(wǎng)絡(luò)連接。一個(gè)是命令連接,另一個(gè)則是訂閱連接。前者用于發(fā)送命令并接收回復(fù);后者則專門用于訂閱Master節(jié)點(diǎn)的 「__sentinel__:hello」 頻道

Sentinel默認(rèn)每隔10s通過命令連接向其正在監(jiān)控的Master節(jié)點(diǎn)發(fā)送「INFO」命令,然后其通過分析Master節(jié)點(diǎn)回復(fù)的結(jié)果。Sentinel一方面可以獲得該Master節(jié)點(diǎn)的相關(guān)信息;另一方面還可以獲得該Master節(jié)點(diǎn)的Slave節(jié)點(diǎn)信息。這也是為什么Sentinel的配置文件中只需配置Master節(jié)點(diǎn)的地址信息,而無需配置Slave節(jié)點(diǎn)的地址信息,即所謂的自動(dòng)發(fā)現(xiàn)
類似地,當(dāng)Sentinel發(fā)現(xiàn)了Master節(jié)點(diǎn)下的Slave節(jié)點(diǎn)后,同樣會(huì)分別創(chuàng)建兩個(gè)網(wǎng)絡(luò)連接(命令連接、訂閱連接)到各Slave節(jié)點(diǎn),如下圖所示。其中,訂閱連接專門用于訂閱各Slave節(jié)點(diǎn)的 「__sentinel__:hello」 頻道。同理,Sentinel也會(huì)通過命令連接以每隔10s的頻率向各Slave節(jié)點(diǎn)發(fā)送「INFO」命令,以獲取Salve節(jié)點(diǎn)等相關(guān)信息

綜上所述,Sentinel通過命令連接向Master、Slave節(jié)點(diǎn)發(fā)送「INFO」命令實(shí)現(xiàn)了對(duì)主從拓?fù)浣Y(jié)構(gòu)的監(jiān)控、維護(hù)
建立Sentinel間網(wǎng)絡(luò)
與此同時(shí)各Sentinel默認(rèn)以每隔2s的頻率通過命令連接向所有其正在監(jiān)視的Master/Slave節(jié)點(diǎn)發(fā)送「PUBLISH命令」,該命令會(huì)向Master/Slave節(jié)點(diǎn)的 「__sentinel__:hello」 頻道發(fā)送一條信息。其包含兩部分內(nèi)容,一部分為該Sentinel自身的IP、Port等信息;另一部分則為Master節(jié)點(diǎn)信息,具體地,如果該Sentinel監(jiān)視的為Master節(jié)點(diǎn),則即為該Master節(jié)點(diǎn)信息;如果該Sentinel監(jiān)視的為Slave節(jié)點(diǎn),則即為該Slave節(jié)點(diǎn)所對(duì)應(yīng)的Master信息
前面提到Sentinel會(huì)與Master/Slave節(jié)點(diǎn)建立訂閱連接,然后Sentinel就會(huì)通過該訂閱連接向Master/Slave節(jié)點(diǎn)發(fā)送SUBSCRIBE命令,以實(shí)現(xiàn)對(duì) 「__sentinel__:hello」 頻道的訂閱。這樣一個(gè)Sentinel實(shí)例就可以基于上述機(jī)制,實(shí)現(xiàn)對(duì)其他Sentinel實(shí)例的自動(dòng)發(fā)現(xiàn)。如下圖所示

至此,各Sentinel實(shí)例之間會(huì)相互建立網(wǎng)絡(luò)連接。但值得一提的是,Sentinel實(shí)例之間只會(huì)建立命令連接,而不會(huì)建立訂閱連接

綜上所述,Sentinel通過 「__sentinel__:hello」 頻道利用發(fā)布/訂閱機(jī)制實(shí)現(xiàn)了對(duì)Sentinel實(shí)例間的網(wǎng)絡(luò)維護(hù)、信息交換
心跳檢測(cè)機(jī)制
各Sentinel實(shí)例默認(rèn)會(huì)以每隔1s的頻率向所有與其創(chuàng)建了命令連接的實(shí)例(包括Mater節(jié)點(diǎn)、Slave節(jié)點(diǎn)、其他Sentinel實(shí)例)發(fā)送「PING命令」,根據(jù)實(shí)例返回的對(duì)PING命令的回復(fù)來判斷實(shí)例是否在線。而實(shí)例對(duì)PING命令的回復(fù)可分為兩種,具體地:
- 「有效回復(fù)」:實(shí)例返回+PONG、-LOADING、-MASTERDOWN三種回復(fù)的其中一種
- 「無效回復(fù)」:實(shí)例返回除+PONG、-LOADING、-MASTERDOWN三種回復(fù)之外的其他回復(fù),或者在指定時(shí)限內(nèi)沒有返回任何回復(fù)
Subjectively Down 主觀下線
前面提到Sentinel會(huì)向其他實(shí)例發(fā)送PING命令進(jìn)行心跳檢測(cè),而如果在指定時(shí)間內(nèi)該Sentinel未收到相應(yīng)實(shí)例的有效回復(fù)。則該Sentinel即會(huì)主觀認(rèn)為該實(shí)例已經(jīng)下線,即所謂的「Subjectively Down」主觀下線(簡(jiǎn)稱「SDOWN」)。具體地,該指定時(shí)間可通過Sentinel配置文件的down-after-milliseconds選項(xiàng)進(jìn)行設(shè)置
Objectively Down 客觀下線
當(dāng)一個(gè)Sentinel判斷Master節(jié)點(diǎn)發(fā)生主觀下線后,為了進(jìn)一步確認(rèn)該Master是否真的下線了。其會(huì)向同樣監(jiān)視該Master節(jié)點(diǎn)的其他Sentinel實(shí)例進(jìn)行詢問。具體地,通過向其他Sentinel實(shí)例發(fā)送 SENTINEL is-master-down-by-addr 命令并收集相應(yīng)的回復(fù)。當(dāng)認(rèn)為該Master節(jié)點(diǎn)已經(jīng)下線的Sentinel實(shí)例總數(shù)(自然也包括當(dāng)前Sentinel實(shí)例)達(dá)到Sentinel配置文件的「quorum」選項(xiàng)時(shí),當(dāng)前Sentinel即會(huì)認(rèn)為該Master節(jié)點(diǎn)客觀上已經(jīng)下線,即所謂的「Objectively Down」客觀下線(簡(jiǎn)稱「ODOWN」)
例如,對(duì)于某Sentinel實(shí)例而言,其監(jiān)視的Master節(jié)點(diǎn)時(shí)使用的配置文件如下所示。當(dāng)該Sentinel判定該Master節(jié)點(diǎn)主觀下線后,會(huì)詢問其他正在監(jiān)視該Master節(jié)點(diǎn)的Sentinel實(shí)例。當(dāng)發(fā)現(xiàn)有3個(gè)其他Sentinel實(shí)例也認(rèn)為該Master節(jié)點(diǎn)已經(jīng)下線了,則此時(shí)該Sentinel實(shí)例即會(huì)認(rèn)為該Master節(jié)點(diǎn)進(jìn)入客觀下線。因?yàn)榧由掀渥陨砉灿?jì)存在4個(gè)Sentinel實(shí)例認(rèn)為該Master節(jié)點(diǎn)下線了,已經(jīng)達(dá)到其配置文件的quorum配置值4的要求了
#?該Sentinel實(shí)例監(jiān)視一個(gè)名為myMaster的Master節(jié)點(diǎn)
#?其中,該Master節(jié)點(diǎn)的IP、Port分別為127.0.0.1、6379
#?其中,quorum配置為4
sentinel?monitor?myMaster?127.0.0.1?6379?4
這里需要補(bǔ)充說明的是,Sentinel僅會(huì)對(duì)Master節(jié)點(diǎn)進(jìn)行主觀、客觀下線的判斷。而對(duì)于Slave節(jié)點(diǎn)、其他Sentinel實(shí)例而言,只會(huì)進(jìn)行主觀下線的判斷
選舉 Sentinel Leader
一旦發(fā)生了客觀下線,那么各Sentinel實(shí)例之間就需要通過投票的方式選舉出一個(gè)Leader來開展、完成后續(xù)的故障轉(zhuǎn)移工作。具體則是通過Raft算法來實(shí)現(xiàn)選舉。這里需要強(qiáng)調(diào)的是在進(jìn)行投票的過程中,一個(gè)Sentinel實(shí)例的票數(shù)需要大于等于 Max( quorum, floor(SentinelNum/2)+1 ) ,其才會(huì)成為本次選舉的Leader
例如在一個(gè)含有11個(gè)Sentinel實(shí)例的Sentinel集群中,如果某Sentinel實(shí)例A的quorum配置值為2,則其需要拿到6票就可以成為L(zhǎng)eader,詳細(xì)計(jì)算過程如下所示
Max(2,?floor(11/2)+1)?=?Math(2,?5+1)?=?Max(2,6)?=?6
而如果另外一個(gè)Sentinel實(shí)例B的的quorum配置值為8,則其需要拿到8票才可以成為L(zhǎng)eader,詳細(xì)計(jì)算過程如下所示
Max(8,?floor(11/2)+1)?=?Math(8,?5+1)?=?Max(8,6)?=?8
至此,對(duì)于Sentinel配置文件的quorum配置項(xiàng)來說。其具有兩個(gè)作用,一方面用于該Sentinel實(shí)例判斷Master節(jié)點(diǎn)發(fā)生主觀下線的條件;另一方面,其決定了該Sentinel實(shí)例在投票選舉期間成為L(zhǎng)eader時(shí)所需票數(shù)的上限。因?yàn)榧词筿uorum配置再低,比如上文的Sentinel實(shí)例A。其最終所需票數(shù)也需要達(dá)到半數(shù)以上才可以成為L(zhǎng)eader
這里做一點(diǎn)補(bǔ)充說明,以解釋為什么Reids官方推薦Sentinel集群中至少應(yīng)該含三個(gè)Sentinel實(shí)例。為了行文簡(jiǎn)潔,這里我先將Sentinel集群中允許Sentinel宕機(jī)的數(shù)量稱為容錯(cuò)性
- 如果Sentinel集群中只有1個(gè)實(shí)例,則顯然容錯(cuò)性為0
- 如果Sentinel集群中只有2個(gè)實(shí)例,即使將quorum配置為1,但半數(shù)以上的投票數(shù)也是2。故其容錯(cuò)性同樣為0。因?yàn)楫?dāng)其中一個(gè)實(shí)例發(fā)生意外宕機(jī)后,剩余的另外一個(gè)實(shí)例由于無法獲取半數(shù)以上的投票,故無法在選舉過程成為L(zhǎng)eader。這樣一旦Master節(jié)點(diǎn)發(fā)生意外,同樣無法進(jìn)行故障轉(zhuǎn)移
- 如果Sentinel集群中有3個(gè)實(shí)例,即使將quorum配置為1,但半數(shù)以上的投票數(shù)同樣是2。故其容錯(cuò)性為1。即使一個(gè)實(shí)例宕機(jī),剩余實(shí)例依然可以順利進(jìn)行Leader選舉
- 如果Sentinel集群中有4個(gè)實(shí)例,即使將quorum配置為1,但半數(shù)以上的投票數(shù)是3。同理,其容錯(cuò)性仍然是1
- 如果Sentinel集群中有5個(gè)實(shí)例,半數(shù)以上的投票數(shù)是3。其容錯(cuò)性為2
- 如果Sentinel集群中有6個(gè)實(shí)例,半數(shù)以上的投票數(shù)是4。其容錯(cuò)性仍然是2
事實(shí)上,通過上面的分析。相信大家已經(jīng)理解為什么在HA高可用架構(gòu)下Sentinel集群中至少應(yīng)該存在3個(gè)Sentinel實(shí)例。進(jìn)一步,從容錯(cuò)性的角度來看,奇數(shù)臺(tái)Sentinel實(shí)例與偶數(shù)臺(tái)Sentinel實(shí)例的容錯(cuò)能力完全一樣。比如3臺(tái)與4臺(tái)的容錯(cuò)性均為2。故從節(jié)約硬件成本的角度考慮,一般會(huì)使用奇數(shù)臺(tái)實(shí)例
Failover 故障轉(zhuǎn)移
在選舉出Sentinel Leader后,Sentinel Leader就需要進(jìn)行真正的Failover故障轉(zhuǎn)移了。其基本流程如下
- 從已經(jīng)下線的Master節(jié)點(diǎn)所屬的所有Slave節(jié)點(diǎn)中,挑選一個(gè)Slave節(jié)點(diǎn)作為新的主節(jié)點(diǎn)
- 讓已經(jīng)下線的Master節(jié)點(diǎn)所屬的所有Slave節(jié)點(diǎn),指向新的主節(jié)點(diǎn)。即從新的主節(jié)點(diǎn)進(jìn)行復(fù)制
- 將已經(jīng)下線的Master節(jié)點(diǎn)設(shè)置為新主節(jié)點(diǎn)的從節(jié)點(diǎn)。這樣當(dāng)這個(gè)已經(jīng)下線的Master節(jié)點(diǎn)后續(xù)重新上線時(shí),其就會(huì)成為新主節(jié)點(diǎn)的從節(jié)點(diǎn)。以避免同時(shí)出現(xiàn)兩個(gè)主節(jié)點(diǎn)的情形
這里對(duì)Sentinel Leader從Slave節(jié)點(diǎn)中選擇新主節(jié)點(diǎn)的方法,作進(jìn)一步說明。其在選擇過程中考慮了以下因素:
- Slave節(jié)點(diǎn)不能處于下線、斷線的狀態(tài)
- Slave節(jié)點(diǎn)與Master節(jié)點(diǎn)斷開連接的時(shí)長(zhǎng)
- Slave節(jié)點(diǎn)處理復(fù)制的偏移量replication offset
- Slave節(jié)點(diǎn)的優(yōu)先級(jí)。優(yōu)先級(jí)小的Slave節(jié)點(diǎn)會(huì)比優(yōu)先級(jí)大的Slave節(jié)點(diǎn)優(yōu)先選中。特別地,對(duì)于優(yōu)先級(jí)為0的Slave節(jié)點(diǎn),則其永遠(yuǎn)不會(huì)選中。具體地,可通過Slave節(jié)點(diǎn)的redis.conf配置文件中replica-priority配置項(xiàng)進(jìn)行設(shè)置
- Redis設(shè)計(jì)與實(shí)現(xiàn) 黃健宏著
