1.概述
redis主從復(fù)制解決了單機下數(shù)據(jù)丟失的問題掰邢,在一主多從的結(jié)構(gòu)下辣之,倘若master出現(xiàn)故障,slaves仍然有數(shù)據(jù)備份狮鸭。此時一個自然而然的想法就涌現(xiàn)出來了:在master不可用的情況下歧蕉,能否重新調(diào)整主從關(guān)系康铭,從slave中選取一個服務(wù)器作為新的master从藤,從而實現(xiàn)redis的高可用。sentinel就是這樣一種解決方案:由一組哨兵(sentinel)實例組成一個sentinel系統(tǒng)懊蒸,該系統(tǒng)保證其自身高可用性的同時榛鼎,監(jiān)控redis主服務(wù)器和該主服務(wù)器所屬的從服務(wù)器鳖孤,當(dāng)主服務(wù)器下線時長超過閾值之后苏揣,由sentinel系統(tǒng)挑選一個從服務(wù)器,將該服務(wù)器升級為新的主服務(wù)器框沟,完成故障轉(zhuǎn)移忍燥。同時隙姿,sentinel還持續(xù)監(jiān)控已下線的服務(wù)器,當(dāng)他重新上線時队丝,將該服務(wù)器設(shè)為新的master下的slave。
sentinel系統(tǒng)的運行流程如圖:
-
假設(shè)現(xiàn)有一個master和3各slave臭墨。通過配置sentinel系統(tǒng)胧弛,使其監(jiān)控這些服務(wù)器
-
當(dāng)master服務(wù)器(server1)下線叶圃, 主從復(fù)制將會被終止践图。同時码党,sentinel感知到server1下線斥黑。
3.master下線時間超過閾值锌奴,sentinel系統(tǒng)開始故障轉(zhuǎn)移鹿蜀。在slave中選取一個服務(wù)器(如server2),作為新的master颠焦,讓其他的服務(wù)器作為server2的從服務(wù)器伐庭。另一邊分冈,sentinel持續(xù)監(jiān)控server1的狀態(tài)。
-
當(dāng)server1重新上線時饺著,sentinel通過SLAVEOF命令將其設(shè)置為server2的從服務(wù)器。
2.sentinel啟動運行全流程
2.1啟動sentinel
創(chuàng)建一個類型為sentinel的redis服務(wù)器梢睛。它本質(zhì)上仍然是一個redis服務(wù)器绝葡,但其工作方式和普通redis服務(wù)器不同腹鹉,主要體現(xiàn)在它需要維護各master和master下slave的在線信息。
1.1. 替換服務(wù)器代碼為Sentinel專用代碼Redis_Server_Port --> Redis_Sentinel_Port; redisCommandTable --> sentinelcmds愉阎。
1.2. 由服務(wù)器初始化Sentinel狀態(tài)榜旦,創(chuàng)建一個sentinelState結(jié)構(gòu)溅呢,主要維護了一個保存masters信息的字典猿挚。
1.5. 服務(wù)器讀取sentinel.conf文件亭饵,完成Sentinel中masters屬性的配置。假設(shè)在配置文件中配置了master1和master2踏兜,那么masters的狀態(tài)如圖八秃。
1.4. 創(chuàng)建與各master的連接昔驱,準(zhǔn)備與master通信
2.2. 獲取主服務(wù)器信息
2.1. 主服務(wù)器本身的信息: run_id: xxx, role:master
2.2 slave信息 ip, port, state, offset ...
獲取到服務(wù)器信息之后纳本,即可更新服務(wù)器實例信息,如下圖:
2.3. 獲取從服務(wù)器信息
當(dāng)有新的從服務(wù)器通過SLAVEOF成為主服務(wù)器的slave時吓笙,master的回復(fù)信息終將會包含該服務(wù)器的信息面睛。Sentinel一方面要為該服務(wù)器創(chuàng)建實例結(jié)構(gòu)尊搬, 另一方面還需要創(chuàng)建到該服務(wù)器的命令連接和訂閱連接佛寿。連接創(chuàng)建后,sentinel每10秒向從服務(wù)器發(fā)送INFO命令狗准,獲取從服務(wù)器的信息腔长,包括run_id, role, masterhost: master_port, 復(fù)制偏移量...
2.4. 以一定頻率向主验残、從服務(wù)器發(fā)送信息
每2秒向所有被監(jiān)視的主、從服務(wù)器發(fā)送 PUBLISH sentinel: hello "<...>"命令鸟召。
2.5. 接收主欧募、從服務(wù)器的信息
通過訂閱連接仆抵,向服務(wù)器發(fā)送 SUBSCRIBE sentinel:hello命令。一臺sentinel像某臺master/slave發(fā)送的信息也會被其他訂閱了該服務(wù)器的sentinel收到舔糖。該功能的作用在于:使各個sentinel之間能通過主/從服務(wù)器相互通信金吗。 根據(jù)收到的消息,如果是自己發(fā)送的旱物,那么就丟棄异袄;如果是其他sentinel發(fā)送的,就根據(jù)信息中的各個參數(shù)更新主服務(wù)器的實例結(jié)構(gòu)迹冤,更新sentinels字典,此時各個sentinel中就可以保存彼此的ip:port橱鹏,接下來創(chuàng)建鏈接并相互通信就順理成章了莉兰。
2.6. 檢測下線狀態(tài)
2.6.1 主觀下線狀態(tài)
sentinel默認每秒向所有與他創(chuàng)建了連接的實例(master, slave, sentinel)發(fā)送PING命令糖荒,通過回復(fù)狀態(tài)來判斷實例是否在線捶朵。每個sentinel對服務(wù)器實例的下線判斷都是依靠它自身與服務(wù)器之間的連接综看,有可能二者之間通信不順暢,導(dǎo)致該sentinel判斷對方下線红碑,但并不意味著對方真的下線了析珊,因此這種情況稱之為主觀下線兔毙;實例是否真的下線了,要依靠所有sentinel投票锡溯。
回復(fù)內(nèi)容只有3種有效: -PONG, -LOADING, -MASTERDOWN
如果一個實例在一定時間內(nèi),連續(xù)向sentinel返回?zé)o效回復(fù)芜茵,則sentinel修改該實例對應(yīng)的狀態(tài)九串,將其標(biāo)記為主觀下線寺鸥。
2.6.2 客觀下線狀態(tài)
當(dāng)一個sentinel將主服務(wù)器標(biāo)記為主觀下線狀態(tài)之后,會向其他監(jiān)視該服務(wù)器的sentinel發(fā)送請求烤低,看他們是否也認為該服務(wù)器處于下線狀態(tài)笆载。當(dāng)認為下線的sentinel超過配置的閾值時,表明客觀下線腻要,將主服務(wù)器實例標(biāo)記為客觀下線狀態(tài)
2.7. 選舉sentinel leader
當(dāng)sentinel將一個主服務(wù)器被判定為客觀下線之后涝登,會發(fā)送請求給監(jiān)視它的各sentinel缀拭,選舉出一個leader sentinel,然后由leader sentinel來進行故障轉(zhuǎn)移。
Sentinel集群正常運行的時候每個節(jié)點epoch相同褐荷,當(dāng)需要故障轉(zhuǎn)移的時候會在集群中選出Leader執(zhí)行故障轉(zhuǎn)移操作嘹悼。Sentinel采用了Raft協(xié)議實現(xiàn)了Sentinel間選舉Leader的算法,不過也不完全跟論文描述的步驟一致其监。Sentinel集群運行過程中故障轉(zhuǎn)移完成限匣,所有Sentinel又會恢復(fù)平等。Leader僅僅是故障轉(zhuǎn)移操作出現(xiàn)的角色锌历。
選舉流程
- 1、某個Sentinel認定master客觀下線的節(jié)點后窗慎,該Sentinel會先看看自己有沒有投過票卤材,如果自己已經(jīng)投過票給其他Sentinel了,在2倍故障轉(zhuǎn)移的超時時間自己就不會成為Leader伏伐。相當(dāng)于它是一個Follower晕拆。
- 2、如果該Sentinel還沒投過票吝镣,那么它就成為Candidate末贾。
- 3整吆、和Raft協(xié)議描述的一樣,成為Candidate拴测,Sentinel需要完成幾件事情
- 1)更新故障轉(zhuǎn)移狀態(tài)為start
- 2)當(dāng)前epoch加1集索,相當(dāng)于進入一個新term汇跨,在Sentinel中epoch就是Raft協(xié)議中的term。
- 3)更新自己的超時時間為當(dāng)前時間隨機加上一段時間函匕,隨機時間為1s內(nèi)的隨機毫秒數(shù)盅惜。
- 4)向其他節(jié)點發(fā)送
is-master-down-by-addr
命令請求投票。命令會帶上自己的epoch咽安。 - 5)給自己投一票蓬推,在Sentinel中,投票的方式是把自己master結(jié)構(gòu)體里的leader和leader_epoch改成投給的Sentinel和它的epoch糕珊。
- 4红选、其他Sentinel會收到Candidate的
is-master-down-by-addr
命令姆另。如果Sentinel當(dāng)前epoch和Candidate傳給他的epoch一樣,他在本輪把票投給了其他Candidate蝶防。投過票給別的Sentinel后间学,在當(dāng)前epoch內(nèi)自己就只能成為Follower印荔。 - 5、Candidate會不斷的統(tǒng)計自己的票數(shù)嘿悬,直到他發(fā)現(xiàn)認同他成為Leader的票數(shù)超過一半而且超過它配置的quorum(quorum可以參考《redis sentinel設(shè)計與實現(xiàn)》)染苛。Sentinel比Raft協(xié)議增加了quorum茶行,這樣一個Sentinel能否當(dāng)選Leader還取決于它配置的quorum畔师。
- 6看锉、如果在一個選舉時間內(nèi),Candidate沒有獲得超過一半且超過它配置的quorum的票數(shù)呻此,自己的這次選舉就失敗了焚鲜。
- 7、如果在一個epoch內(nèi)忿磅,沒有一個Candidate獲得更多的票數(shù)葱她。那么等待超過2倍故障轉(zhuǎn)移的超時時間后吨些,Candidate增加epoch重新投票豪墅。
- 8辆脸、如果某個Candidate獲得超過一半且超過它配置的quorum的票數(shù)啡氢,那么它就成為了Leader。
- 9亭枷、與Raft協(xié)議不同叨粘,Leader并不會把自己成為Leader的消息發(fā)給其他Sentinel升敲。其他Sentinel等待Leader從slave選出master后轰传,檢測到新的master正常工作后,就會去掉客觀下線的標(biāo)識港庄,從而不需要進入故障轉(zhuǎn)移流程鹏氧。
ref:Raft協(xié)議實戰(zhàn)之Redis Sentinel的選舉Leader源碼解析
2.8. 故障轉(zhuǎn)移
8.1. 由leader sentinel重新選取新的master
8.2 修改從服務(wù)器的復(fù)制目標(biāo)
8.3 監(jiān)控舊的master实蓬,上線后將其設(shè)置為新的master下的slave