Redis哨兵機(jī)制的使用詳解
一.哨兵機(jī)制基本解讀
主庫發(fā)生故障了,如何不間斷的服務(wù)?
哨兵模式:有效的解決主從庫自動(dòng)切換的關(guān)鍵機(jī)制

在Redis中如果從庫發(fā)生故障了,客戶端可以繼續(xù)向主庫和其他從庫發(fā)消息,進(jìn)行相關(guān)操作。但是如果主庫故障了,直接影響到從庫的同步操作(從庫沒有相應(yīng)主庫進(jìn)行相關(guān)數(shù)據(jù)復(fù)制操作了)和沒有實(shí)例來支持客戶端進(jìn)行寫操作。
把從庫切換成主庫,需要涉及三個(gè)問題:
- 主庫真的掛了嗎?
- 應(yīng)該選擇哪一個(gè)從庫來切換成主庫?
- 怎么把新主庫的信息通知給從庫和客戶端呢?
1.哨兵機(jī)制的基本流程
哨兵機(jī)制,在主從庫實(shí)例運(yùn)行的時(shí)候,就在運(yùn)行。哨兵機(jī)制主要的行為就是監(jiān)控。
1.1哨兵監(jiān)控
哨兵進(jìn)程在運(yùn)行過程中會(huì)周期性的給所有主從庫發(fā)送PING命令,檢測(cè)他們是否還在線運(yùn)行。如果從庫沒有在規(guī)定時(shí)間內(nèi)響應(yīng)哨兵的PING命令,哨兵就會(huì)把它標(biāo)記為“下線狀態(tài)”。同樣,如果主庫沒有在規(guī)定時(shí)間內(nèi)響應(yīng)哨兵的PING命令,哨兵也會(huì)把主庫標(biāo)記為“下線狀態(tài)”,然后開始自動(dòng)切換主庫的流程。
1.2自動(dòng)切換主庫流程
- 這個(gè)流程首先執(zhí)行的是哨兵的第二個(gè)任務(wù):選主。主庫掛了之后,哨兵需要從眾多從庫中,按照一定規(guī)則選擇一個(gè)從庫實(shí)例,把它作為更新的主庫。這一步完成后,集群里就會(huì)有新的主庫了。
- 然后執(zhí)行的是最后一個(gè)任務(wù):通知。在執(zhí)行任務(wù)通知時(shí),哨兵會(huì)把新主庫的信息發(fā)送給其他所有從庫,讓他們執(zhí)行replicaof命令,和新主庫建立好連接,并且進(jìn)行數(shù)據(jù)復(fù)制。同時(shí),哨兵會(huì)把新主庫連接信息給客戶端,讓他把新的請(qǐng)求發(fā)送到新主庫上。

在這三個(gè)任務(wù)中通知任務(wù)相對(duì)簡(jiǎn)單,只需要給從庫和客戶端發(fā)送新主庫的信息,讓他們跟新主庫連接就行,并不涉及決策邏輯。但是在監(jiān)控和選主這兩個(gè)任務(wù)中,哨兵需要作出兩個(gè)決策:
- 在監(jiān)控任務(wù)中,哨兵需要決策主庫是否處于下線狀態(tài)
- 在選主任務(wù)中,哨兵也要決定選取那個(gè)從庫實(shí)例作為新主庫。
如何判斷主庫是否下線?
2.主庫是否下線判斷
主庫是否下線判斷分為兩種“主觀下線”和”客觀下線“。
2.1.主觀下線
主觀下線:
- 哨兵機(jī)制會(huì)給主從庫發(fā)送PING命令,檢測(cè)他自己和主從庫的網(wǎng)絡(luò)連接情況,用來判斷實(shí)例的狀態(tài)。
- 如果哨兵發(fā)現(xiàn)主從庫的響應(yīng)時(shí)間超時(shí)了,就會(huì)給主從庫標(biāo)記為“主觀下線”。
誤判:
- 但是會(huì)出現(xiàn)一種情況,哨兵誤判了,主從庫并沒有故障,主庫也并沒有下線,哨兵誤判他下線了。誤判一般發(fā)生在:集群網(wǎng)絡(luò)壓力大,網(wǎng)絡(luò)擁塞,或者主庫本身壓力較大的情況下。
- 一旦哨兵判斷主庫下線了,就需要進(jìn)行選主,主從庫同步等一系列操作,就會(huì)增加額外的計(jì)算和通信開銷。
- 所以需要減少誤判。
- 怎么減少誤判呢?
- 引入多幾個(gè)哨兵進(jìn)行協(xié)商判斷,也就是哨兵集群。
哨兵集群:
- 通常由多個(gè)實(shí)例組成的集群模式進(jìn)行部署。
- 引入多個(gè)哨兵實(shí)例進(jìn)行判斷,避免單個(gè)哨兵因?yàn)榫W(wǎng)絡(luò)不好造成的誤判主庫下線的情況。
- 多個(gè)哨兵網(wǎng)絡(luò)同時(shí)不穩(wěn)定的概率小,同時(shí)誤判的概率也小了。
2.2客觀下線
在判斷主庫是否下線時(shí),不能由一個(gè)哨兵說了算,要大多數(shù)哨兵,都判斷主庫已經(jīng)“主觀下線”,主庫才會(huì)標(biāo)記為”客觀下線“,這個(gè)說法表明主庫下線已經(jīng)成為了客觀事實(shí),判斷原理就是:少數(shù)服從多數(shù)。

客觀下線:當(dāng)有N個(gè)集群時(shí),當(dāng)有N/2+1個(gè)集群已經(jīng)判斷主庫“主觀下線”,才能最終判斷主庫“客觀下線”。減少誤判帶來的主從庫切換開銷。(有幾個(gè)實(shí)例來作出主庫“主觀下線”的判斷才可以,由Redis管理員自信設(shè)定)。
3.主從切換機(jī)制:主庫下線了就要進(jìn)行主從切換了
如何選定新主庫?
一般來說,哨兵選擇新主庫的過程可以稱為“篩選+打分”。就是在多個(gè)實(shí)例從庫中,按照一定的篩選條件,把不符合條件的從庫去掉。然后在按照一定的規(guī)則,給剩下的從庫逐個(gè)打分,將得分最高的從庫選為新主庫。

3.1篩選條件
不僅僅要判斷從庫當(dāng)前的狀態(tài),還要判斷他之前的網(wǎng)絡(luò)連接狀態(tài)。如果之前從庫跟主庫斷聯(lián)次數(shù)超過了閾值,那么有有理由詳細(xì)這個(gè)從庫的網(wǎng)絡(luò)連接狀態(tài)不是很好,可以把它篩選掉。雖然現(xiàn)在他在運(yùn)行,但是萬一過一會(huì)斷掉了,就需要重新選主,所以需要判斷她之前的狀態(tài)。
具體怎么判斷呢?
使用配置項(xiàng)down-after-milliseconds*10。其中,down-after-milliseconds是我們認(rèn)定是從庫斷聯(lián)的最大時(shí)間。如果在down-after-milliseconds毫秒內(nèi),主從節(jié)點(diǎn)都沒有網(wǎng)絡(luò)連接上,那么就認(rèn)為從庫斷聯(lián)了。如果斷聯(lián)時(shí)間超過了10次就認(rèn)為,這個(gè)從庫的網(wǎng)絡(luò)轉(zhuǎn)態(tài)不是很好,不適合做主庫。
3.2打分規(guī)則
可以分別按照三個(gè)規(guī)則進(jìn)行打分:從庫優(yōu)先級(jí)、從庫復(fù)制進(jìn)度、以及從庫ID號(hào)
只需要在某一輪得分最高,那么他就是新主庫,選主過程到此結(jié)束,要是沒有出現(xiàn)得分最高的,那么久進(jìn)行下一輪。
第一輪:優(yōu)先級(jí)slave-priority最高的從庫得分高
用戶可以通過slave-priority配置項(xiàng),給不同的從庫設(shè)置不同優(yōu)先級(jí)。比如,你有兩個(gè)從庫,它們的內(nèi)存大
小不一樣,你可以手動(dòng)給內(nèi)存大的實(shí)例設(shè)置一個(gè)高優(yōu)先級(jí)。在選主時(shí),哨兵會(huì)給優(yōu)先級(jí)高的從庫打高分,如果有一個(gè)從庫優(yōu)先級(jí)最高,那么它就是新主庫了。如果從庫的優(yōu)先級(jí)都一樣,那么哨兵開始第二輪打分。
第二輪:和舊主庫同步程度最接近的從庫得分高
如果選擇和舊主庫同步最接近的從庫作為主庫,新主庫上邊就會(huì)有最新的數(shù)據(jù)。
如何判斷從庫和主庫的同步進(jìn)度呢?(復(fù)制進(jìn)度)
主從庫同步的時(shí)有個(gè)命令傳播的過程,在這個(gè)過程中,主庫會(huì)用master-repl-offset記錄,當(dāng)前的最新寫操作在repl-backlog-buffer的中位置,而從庫會(huì)用slave-repl-offset記錄復(fù)制的進(jìn)度。
所以我們需要找到master-repl-offset,slave-repl-offset最接近的從庫。得分就高,就會(huì)被選為新主庫。如果slave-repl-offset相同,就會(huì)進(jìn)行下一輪的打分。
就像下圖所示,舊主庫的master_repl_offset是1000,從庫1、2和3的slave_repl_offset分別是950、990和900,那么,從庫2就應(yīng)該被選為新主庫。

第三輪:ID號(hào)小的從庫得分高
每個(gè)實(shí)例都會(huì)有一個(gè)id,這個(gè)ID類似于從庫的編號(hào)。Redis選主時(shí),有一個(gè)規(guī)定:在優(yōu)先級(jí)和復(fù)制進(jìn)度相同的情況下,ID越小的得分越高。
3.3主從切換總結(jié)
首先哨兵機(jī)制會(huì)根據(jù)在線狀態(tài),網(wǎng)絡(luò)狀態(tài),過濾篩選掉一部分不符合要求的從庫。然后按照優(yōu)先級(jí),復(fù)制進(jìn)度,ID大小對(duì)從庫進(jìn)行打分,得分最高的選為新主庫。
4.哨兵機(jī)制總結(jié)
主從集群數(shù)據(jù)同步,保證了數(shù)據(jù)的可靠性。主庫發(fā)生故障時(shí),自動(dòng)的主從切換是服務(wù)不間斷的關(guān)鍵支撐。
Redis的哨兵機(jī)制自動(dòng)完成了以下三大功能,從而實(shí)現(xiàn)了主從庫的自動(dòng)切換,可以降低Redis集群的運(yùn)維開銷:
- 監(jiān)控主庫運(yùn)行狀態(tài),并判斷主庫是否客觀下線;
- 在主庫客觀下線后,選取新主庫;
- 選出新主庫后,通知從庫和客戶端。

為了降低誤判率,在實(shí)際應(yīng)用時(shí),哨兵機(jī)制通常來用多實(shí)例的方式進(jìn)行部署,多個(gè)哨兵實(shí)例通過“少數(shù)服從多數(shù)”的原則,來判斷主庫是否客觀下線。一般來說,我們可以部署三個(gè)哨兵,如果有兩個(gè)哨兵認(rèn)定主庫“主觀下線”,就可以開始切換過程。當(dāng)然,如果你希望進(jìn)一步提升判斷準(zhǔn)確率,也可以再適當(dāng)增加哨兵個(gè)數(shù),比如說使用五個(gè)哨兵。
哨兵集群中有實(shí)例掛了,怎么辦,會(huì)影響主庫狀態(tài)判斷和選主嗎?
簡(jiǎn)單說結(jié)論:存在故障節(jié)點(diǎn)時(shí),只要集群中大多數(shù)節(jié)點(diǎn)狀態(tài)正常,集群依舊可以對(duì)外提供服務(wù)
哨兵集群多數(shù)實(shí)例達(dá)成共識(shí),判斷出主庫“客觀下線”后,由哪個(gè)實(shí)例來執(zhí)行主從切換呢?
哨兵集群判斷出主庫“主觀下線”后,會(huì)選出一個(gè)“哨兵領(lǐng)導(dǎo)者”,之后整個(gè)過程由它來完成主從切換。
哨兵在操作主從切換的過程中,客戶端能否正常地進(jìn)行請(qǐng)求操作?
如果客戶端使用了讀寫分離,那么讀請(qǐng)求可以在從庫上正常執(zhí)行,不會(huì)受到影響。但是由于此時(shí)主庫已經(jīng)掛了,而且哨兵還沒有選出新的主庫,所以在這期間寫請(qǐng)求會(huì)失敗,失敗持續(xù)的時(shí)間=哨兵切換主從的時(shí)間+客戶端感知到新主庫的時(shí)間.
如果不想讓業(yè)務(wù)感知到異常,客戶端只能把寫失敗的請(qǐng)求先緩存起來或?qū)懭胂㈥?duì)列中間件中,等哨兵切換完主從后,再把這些寫請(qǐng)求發(fā)給新的主庫,但這種場(chǎng)景只適合對(duì)寫入請(qǐng)求返回值不敏感的業(yè)務(wù),而且還需要業(yè)務(wù)層做適配,另外主從切換時(shí)間過長(zhǎng),也會(huì)導(dǎo)致客戶端或消息隊(duì)列中間件緩存寫請(qǐng)求過多,切換完成之后重放這些請(qǐng)求的時(shí)間變長(zhǎng)。
哨兵檢測(cè)主庫多久沒有響應(yīng)就提升從庫為新的主庫,這個(gè)時(shí)間是可以配置的(down-after-milliseconds參數(shù))。配置的時(shí)間越短,哨兵越敏感,哨兵集群認(rèn)為主庫在短時(shí)間內(nèi)連不上就會(huì)發(fā)起主從切換,這種配置很可能因?yàn)榫W(wǎng)絡(luò)擁塞但主庫正常而發(fā)生不必要的切換,當(dāng)然,當(dāng)主庫真正故障時(shí),因?yàn)榍袚Q得及時(shí),對(duì)業(yè)務(wù)的影響最小。如果配置的時(shí)間比較長(zhǎng),哨兵越保守,這種情況可以減少哨兵誤判的概率,但是主庫故障發(fā)生時(shí),業(yè)務(wù)寫失敗的時(shí)間也會(huì)比較久,緩存寫請(qǐng)求數(shù)據(jù)量越多。
二.哨兵掛了
如果有哨兵實(shí)例在運(yùn)行時(shí)發(fā)生了故障,主從庫還能正常切換嗎?
實(shí)際上,一旦多個(gè)實(shí)例組成了哨兵集群,即使有哨兵實(shí)例出現(xiàn)故障掛掉了,其他哨兵還能繼續(xù)協(xié)作完成主庫切換的工作,包括判定主庫是不是處于下線狀態(tài),選擇新主庫,以及通知從庫和客戶端。
如果你部署過哨兵集群的話就會(huì)知道,在配置哨兵的信息時(shí),我們只需要用到下面的這個(gè)配置項(xiàng),設(shè)置主的IP和端口,并沒有配置其他哨兵的連接信息。
sentinel monitor <master-name> <ip> <redis-port> <quorum>
哨兵既然不知道彼此的地址,怎么組成哨兵集群呢?
1.基于pub/sub機(jī)制的哨兵集群的組成
哨兵能被互相發(fā)現(xiàn)的原因:Redis提供的pub/sub機(jī)制(發(fā)布/訂閱機(jī)制)
1.1哨兵之間互相被發(fā)現(xiàn)過程
哨兵只要跟主庫建立起了連接,就可以在主庫上發(fā)布信息,發(fā)布自己的連接信息(ip和端口號(hào))。同時(shí)也可以從主庫上訂閱信息,獲取其它哨兵發(fā)布的連接信息。當(dāng)多個(gè)哨兵在主庫上進(jìn)行了發(fā)布和訂閱后,他們就互相知道彼此的ip地址和端口號(hào)。
除了哨兵實(shí)例,我們自己編寫的應(yīng)用程序也可以通過Redis進(jìn)行消息發(fā)布和訂閱。
Redis如何區(qū)分不同的應(yīng)用程序?
Redis通過頻道的方式。對(duì)消息進(jìn)行歸類管理,區(qū)分不同的應(yīng)用消息。頻道其實(shí)就是消息類型,當(dāng)消息類型相同時(shí),就屬于一個(gè)頻道。只有訂閱了同一個(gè)頻道的應(yīng)用才能通過發(fā)布的消息進(jìn)行信息交換。
在主從集群中,主庫存在“__sentinel__:hello”的頻道,不同哨兵通過實(shí)現(xiàn)他來相互發(fā)現(xiàn),實(shí)現(xiàn)互相通信。
1.2哨兵消息互通說明
例如:在下圖中,哨兵1把自己的IP (17216.19.3) 和端口26579) 發(fā)布到“_sentinel_:hello”頻道上,哨兵2和3訂閱了該頻道。那么此時(shí),哨兵2和3就可以從這個(gè)頻道直接獲取哨兵1的IP地址和端口號(hào)。
然后,哨兵2、3可以和哨兵1建立網(wǎng)絡(luò)連接。通過這個(gè)方式,哨兵2和3也可以建立網(wǎng)絡(luò)連接,這樣一來,哨兵集群就形成了。它們相互間可以通過網(wǎng)絡(luò)連接進(jìn)行通信,比如說對(duì)主庫有沒有下線這件事兒進(jìn)行判斷和協(xié)商

哨兵除了需要彼此建立連接形成集群外還需要和從庫建立連接。因?yàn)樵谏诒O(jiān)控任務(wù)中,哨兵需要對(duì)主從庫進(jìn)行心跳判斷,而且在主從庫切換完成后,還需要通知從庫,讓他們和新主庫進(jìn)行同步。
哨兵如何跟從庫簡(jiǎn)歷連接?如何知道從庫的ip地址和端口呢?
1.3哨兵與從庫建立連接:INFO命令
當(dāng)哨兵給主庫發(fā)送INFO命令時(shí),主庫接收命令后,會(huì)將從庫列表返回給哨兵。哨兵接收從庫列表連接信息后,會(huì)和每個(gè)從庫建立連接,并且在這個(gè)連接上持續(xù)的對(duì)從庫進(jìn)行監(jiān)控。

通過pub/sub機(jī)制,哨兵之間建立哨兵集群,又通過發(fā)送INFO命令,獲取從庫連接信息 ,哨兵與從庫建立連接,進(jìn)行監(jiān)控。主從庫切換后,客戶端需要知道新主庫的連接信息,才能像新主庫發(fā)送信息。因此哨兵還需要完成將新主庫信息告訴客戶端的任務(wù)。
在實(shí)際使用哨兵時(shí),我們有時(shí)會(huì)遇到這樣的問題:如何在客戶端通過監(jiān)控了解哨兵進(jìn)行主從切換的過程呢?比如說,主從切換進(jìn)行到哪一步了? 這其實(shí)就是要求,客戶端能夠獲取到哨兵集群在監(jiān)控、選主、切換這個(gè)過程中發(fā)生的各種事件.
1.4哨兵與客戶端間的信息同步
基于pub/sub機(jī)制的客戶端事件的通知
從本質(zhì)上說,哨兵就是一個(gè)運(yùn)行在特定模式下的Redis實(shí)例,只不過它并不完成服務(wù)請(qǐng)求操作,只是完成監(jiān)控、選主和通知的任務(wù)。所以,每個(gè)哨兵實(shí)例也提供pub/sub機(jī)制,客戶端可以從哨兵訂閱消息。哨兵提供的消息訂閱頻道有很多,不同頻道包含了主從庫切換過程中的不同關(guān)鍵事件
常用事件:
事件 | 相關(guān)頻道 |
主庫下線事件 | +sdown(實(shí)例進(jìn)入“主觀下線”狀態(tài)) |
-sdown(實(shí)例退出“主觀下線”狀態(tài)) | |
+odown(實(shí)例進(jìn)入“客觀下線”狀態(tài)) | |
-odown(實(shí)例退出“客觀下線”狀態(tài)) | |
從庫重新配置事件 | +slave-reconf-sent(哨兵發(fā)送SLACEOF命令重新配置從庫) |
+slave-reconf-inprog(從庫配置新主庫,但尚未進(jìn)行同步) | |
+slave-reconf-done(從庫配置新主庫,且與新主庫同步完成) | |
新主庫切換 | +switch-master(主庫地址變化) |
知道了這些頻道之后,就可以讓客戶端從哨兵這里訂閱消息了。具體的操作步驟是,客戶端讀取哨兵的配置文件后,可以獲得哨兵的地址和端口,和哨兵建立網(wǎng)絡(luò)連接。然后,可以在客戶端執(zhí)行訂閱命令,來獲取不同的事件消息。
舉個(gè)例子,你可以執(zhí)行如下命令,來訂閱“所有實(shí)例進(jìn)入客觀下線狀態(tài)的事件”:
subscribe +odown
訂閱所有頻道
PSUBSCRIBE *
當(dāng)哨兵把新主庫選擇出來后,客戶端就會(huì)看到下面的switch-master事件。這個(gè)事件表示主庫已經(jīng)切換了,新主庫的IP地址和端口信息已經(jīng)有了。這個(gè)時(shí)候,客戶端就可以用這里面的新主庫地址和端口進(jìn)行通信了。
switch-master <master name> <oldip><oldport> <newport>
通過事件通知,客戶端不僅僅可以在主從切換后得到新主庫的連接信息,還可以監(jiān)控得到主從庫切換過程中發(fā)生的各個(gè)重要事件。這樣客戶端就可以知道主從切換到哪一步了,有助于了解切換速度。
總結(jié):有了pub/sub機(jī)制,哨兵可以和從庫之間,哨兵與哨兵之間,哨兵與客戶端之間建立起連接。主庫下線判斷,選主依據(jù)哨兵集群的監(jiān)控、選主和通知三個(gè)任務(wù)基本上可以正常工作了。
主從故障后,集群存在多個(gè)實(shí)例,怎么確定由哪個(gè)哨兵來進(jìn)行實(shí)際的主從切換呢?
2.哪個(gè)哨兵執(zhí)行主從切換?
其實(shí)由哪個(gè)哨兵進(jìn)行主從切換的過程,其實(shí)跟選主一樣也是一個(gè)“投票仲裁”的過程。
2.1從哨兵選主,主要過程開始說起
任何一個(gè)實(shí)例只要自身判斷主庫“主觀下線”后,就會(huì)給其他實(shí)例發(fā)送is-master-down-by-addr命令。接著,其他實(shí)例會(huì)根據(jù)自己和主庫的連接情況,做出Y或N的響應(yīng),Y相當(dāng)于贊成票,N相當(dāng)于反對(duì)票。

一個(gè)哨兵獲得了仲裁所需的贊成票數(shù)后,就可以標(biāo)記主庫為“客觀下線”。這個(gè)所需的贊成票數(shù)是通過哨兵配置文件中的 quorum 配置項(xiàng)設(shè)定的。例如,現(xiàn)在有 5 個(gè)哨兵,quorum 配置的是 3,那么,一個(gè)哨兵需要 3 張贊成票,就可以標(biāo)記主庫為“客觀下線”了。這 3 張贊成票包括哨兵自己的一張贊成票和另外兩個(gè)哨兵的贊成票。
2.2哨兵選出Leader過程:Leader選舉
此時(shí),這個(gè)哨兵就可以再給其他哨兵發(fā)送命令,表明希望由自己來執(zhí)行主從切換,并讓所有其他哨兵進(jìn)行投票。這個(gè)投票過程稱為“Leader 選舉”。因?yàn)樽罱K執(zhí)行主從切換的哨兵稱為 Leader,投票過程就是確定 Leader。
在投票過程中,任何一個(gè)想成為 Leader 的哨兵,要滿足兩個(gè)條件:第一,拿到半數(shù)以上的贊成票;第二,拿到的票數(shù)同時(shí)還需要大于等于哨兵配置文件中的 quorum 值。以 3 個(gè)哨兵為例,假設(shè)此時(shí)的 quorum 設(shè)置為 2,那么,任何一個(gè)想成為 Leader 的哨兵只要拿到 2 張贊成票,就可以了。
具體通過下圖講解:

在 T1 時(shí)刻,S1 判斷主庫為“客觀下線”,它想成為 Leader,就先給自己投一張贊成票,然后分別向 S2 和 S3 發(fā)送命令,表示要成為 Leader。
在 T2 時(shí)刻,S3 判斷主庫為“客觀下線”,它也想成為 Leader,所以也先給自己投一張贊成票,再分別向 S1 和 S2 發(fā)送命令,表示要成為 Leader。
在 T3 時(shí)刻,S1 收到了 S3 的 Leader 投票請(qǐng)求。因?yàn)?S1 已經(jīng)給自己投了一票 Y,所以它不能再給其他哨兵投贊成票了,所以 S1 回復(fù) N 表示不同意。同時(shí),S2 收到了 T2 時(shí) S3 發(fā)送的 Leader 投票請(qǐng)求。因?yàn)?S2 之前沒有投過票,它會(huì)給第一個(gè)向它發(fā)送投票請(qǐng)求的哨兵回復(fù) Y,給后續(xù)再發(fā)送投票請(qǐng)求的哨兵回復(fù) N,所以,在 T3 時(shí),S2 回復(fù) S3,同意 S3 成為 Leader。
在 T4 時(shí)刻,S2 才收到 T1 時(shí) S1 發(fā)送的投票命令。因?yàn)?S2 已經(jīng)在 T3 時(shí)同意了 S3 的投票請(qǐng)求,此時(shí),S2 給 S1 回復(fù) N,表示不同意 S1 成為 Leader。發(fā)生這種情況,是因?yàn)?S3 和 S2 之間的網(wǎng)絡(luò)傳輸正常,而 S1 和 S2 之間的網(wǎng)絡(luò)傳輸可能正好擁塞了,導(dǎo)致投票請(qǐng)求傳輸慢了。
最后,在 T5 時(shí)刻,S1 得到的票數(shù)是來自它自己的一票 Y 和來自 S2 的一票 N。而 S3 除了自己的贊成票 Y 以外,還收到了來自 S2 的一票 Y。此時(shí),S3 不僅獲得了半數(shù)以上的 Leader 贊成票,也達(dá)到預(yù)設(shè)的 quorum 值(quorum 為 2),所以它最終成為了 Leader。接著,S3 會(huì)開始執(zhí)行選主操作,而且在選定新主庫后,會(huì)給其他從庫和客戶端通知新主庫的信息。
如果 S3 沒有拿到 2 票 Y,那么這輪投票就不會(huì)產(chǎn)生 Leader。哨兵集群會(huì)等待一段時(shí)間(也就是哨兵故障轉(zhuǎn)移超時(shí)時(shí)間的 2 倍),再重新選舉。這是因?yàn)?,哨兵集群能夠進(jìn)行成功投票,很大程度上依賴于選舉命令的正常網(wǎng)絡(luò)傳播。如果網(wǎng)絡(luò)壓力較大或有短時(shí)堵塞,就可能導(dǎo)致沒有一個(gè)哨兵能拿到半數(shù)以上的贊成票。所以,等到網(wǎng)絡(luò)擁塞好轉(zhuǎn)之后,再進(jìn)行投票選舉,成功的概率就會(huì)增加。
需要注意的是,如果哨兵集群只有 2 個(gè)實(shí)例,此時(shí),一個(gè)哨兵要想成為 Leader,必須獲得 2 票,而不是 1 票。所以,如果有個(gè)哨兵掛掉了,那么,此時(shí)的集群是無法進(jìn)行主從庫切換的。因此,通常我們至少會(huì)配置 3 個(gè)哨兵實(shí)例。這一點(diǎn)很重要,你在實(shí)際應(yīng)用時(shí)可不能忽略了。
哨兵不會(huì)同時(shí)投票給自己的原因?
要發(fā)生S1、S2和S3同時(shí)同自己投票的情況,這需要這三個(gè)哨兵基本同時(shí)判定了主庫客觀下線。但是,不同哨兵的網(wǎng)絡(luò)連接、系統(tǒng)壓力不完全一樣,接收到下線協(xié)商消息的時(shí)間也可能不同,所以,它們同時(shí)做出主庫客觀下線判定的概率較小,一般都有個(gè)先后關(guān)系。文章中的例子,就是S1、S3先判定,S2一直沒有判定。
哨兵對(duì)主從庫進(jìn)行的在線狀態(tài)檢查等操作,是屬于一種時(shí)間事件,用一個(gè)定時(shí)器來完成,一般來說每100ms執(zhí)行一次這些事件。每個(gè)哨兵的定時(shí)器執(zhí)行周期都會(huì)加上一個(gè)小小的隨機(jī)時(shí)間偏移,目的是讓每個(gè)哨兵執(zhí)行上述操作的時(shí)間能稍微錯(cuò)開些,也是為了避免它們都同時(shí)判定主庫下線,同時(shí)選舉Leader。
Redis 1主4從,5個(gè)哨兵,哨兵配置quorum為2,如果3個(gè)哨兵故障,當(dāng)主庫宕機(jī)時(shí),哨兵能否判斷主庫“客觀下線”?能否自動(dòng)切換?
1、哨兵集群可以判定主庫“主觀下線”。由于quorum=2,所以當(dāng)一個(gè)哨兵判斷主庫“主觀下線”后,詢問另外一個(gè)哨兵后也會(huì)得到同樣的結(jié)果,2個(gè)哨兵都判定“主觀下線”,達(dá)到了quorum的值,因此,哨兵集群可以判定主庫為“客觀下線”。
2、但哨兵不能完成主從切換。哨兵標(biāo)記主庫“客觀下線后”,在選舉“哨兵領(lǐng)導(dǎo)者”時(shí),一個(gè)哨兵必須拿到超過多數(shù)的選票(5/2+1=3票)。但目前只有2個(gè)哨兵活著,無論怎么投票,一個(gè)哨兵最多只能拿到2票,永遠(yuǎn)無法達(dá)到多數(shù)選票的結(jié)果。
哨兵實(shí)例是不是越多越好?
- 并不是,我們也看到了,哨兵在判定“主觀下線”和選舉“哨兵領(lǐng)導(dǎo)者”時(shí),都需要和其他節(jié)點(diǎn)進(jìn)行通信,交換信息,哨兵實(shí)例越多,通信的次數(shù)也就越多,而且部署多個(gè)哨兵時(shí),會(huì)分布在不同機(jī)器上,節(jié)點(diǎn)越多帶來的機(jī)器故障風(fēng)險(xiǎn)也會(huì)越大,這些問題都會(huì)影響到哨兵的通信和選舉,出問題時(shí)也就意味著選舉時(shí)間會(huì)變長(zhǎng),切換主從的時(shí)間變久。
- 哨兵實(shí)例越多,誤判率會(huì)越低,但是在判定主庫下線和選舉Leader時(shí),實(shí)例需要拿到的贊成票數(shù)也越多,等待所有哨兵投完票的時(shí)間可能也會(huì)相應(yīng)增加,主從庫切換的時(shí)間也會(huì)變長(zhǎng),客戶端容易堆積較多的請(qǐng)求操作,可能會(huì)導(dǎo)致客戶端請(qǐng)求溢出,從而造成請(qǐng)求丟失。如果業(yè)務(wù)層對(duì)Redis的操作有響應(yīng)時(shí)間要求,就可能會(huì)因?yàn)樾轮鲙煲恢睕]有選定,新操作無法執(zhí)行而發(fā)生超時(shí)報(bào)警。
- 調(diào)大down-after-milliseconds后,可能會(huì)導(dǎo)致這樣的情況:主庫實(shí)際已經(jīng)發(fā)生故障了,但是哨兵過了很長(zhǎng)時(shí)間才判斷出來,這就會(huì)影響到Redis對(duì)業(yè)務(wù)的可用性。
調(diào)大down-after-milliseconds值,對(duì)減少誤判是不是有好處?
是有好處的,適當(dāng)調(diào)大down-after-milliseconds值,當(dāng)哨兵與主庫之間網(wǎng)絡(luò)存在短時(shí)波動(dòng)時(shí),可以降低誤判的概率。但是調(diào)大down-after-milliseconds值也意味著主從切換的時(shí)間會(huì)變長(zhǎng),對(duì)業(yè)務(wù)的影響時(shí)間越久,我們需要根據(jù)實(shí)際場(chǎng)景進(jìn)行權(quán)衡,設(shè)置合理的閾值。
3.總結(jié):哨兵關(guān)鍵機(jī)制(哨兵聯(lián)系主從客哨兵,Leader選主)
我們?cè)诮鉀Q一個(gè)系統(tǒng)問題的時(shí)候,會(huì)引入一個(gè)新機(jī)制,或者設(shè)計(jì)一層新功能,哨兵主要內(nèi)容:為了實(shí)現(xiàn)主從切換,我們引入了哨兵;為了避免單個(gè)哨兵故障后無法進(jìn)行主從切換,以及為了減少誤判率,又引入了哨兵集群;哨兵集群又需要有一些機(jī)制來支撐它的正常運(yùn)行。
3.1哨兵集群的這些關(guān)鍵機(jī)制
- 基于 pub/sub 機(jī)制的哨兵集群組成過程;
- 基于 INFO 命令的從庫列表,這可以幫助哨兵和從庫建立連接;
- 基于哨兵自身的 pub/sub 功能,這實(shí)現(xiàn)了客戶端和哨兵之間的事件通知。
對(duì)于主從切換,當(dāng)然不是哪個(gè)哨兵想執(zhí)行就可以執(zhí)行的,否則就亂套了。所以,這就需要哨兵集群在判斷了主庫“客觀下線”后,經(jīng)過投票仲裁,選舉一個(gè) Leader 出來,由它負(fù)責(zé)實(shí)際的主從切換,即由它來完成新主庫的選擇以及通知從庫與客戶端。
最后,我想再給你分享一個(gè)經(jīng)驗(yàn):要保證所有哨兵實(shí)例的配置是一致的,尤其是主觀下線的判斷值 down-after-milliseconds。這個(gè)值在不同的哨兵實(shí)例上配置不一致,導(dǎo)致哨兵集群一直沒有對(duì)有故障的主庫形成共識(shí),也就沒有及時(shí)切換主庫,最終的結(jié)果就是集群服務(wù)不穩(wěn)定。所以,你一定不要忽略這條看似簡(jiǎn)單的經(jīng)驗(yàn)。
三.哨兵全部總結(jié)
1.哨兵怎么跟主庫連接
哨兵與主庫直接相關(guān)聯(lián),手動(dòng)設(shè)置,可以設(shè)置多個(gè)哨兵
2.哨兵怎么給從庫發(fā)消息
哨兵給主庫發(fā)送info命令,主庫返回從庫的slave集合,與從庫建立連接,把新主庫的信息發(fā)送給從庫
3.哨兵怎么跟客戶端聯(lián)系
client訂閱Sentinel的某一個(gè)頻道,該頻道里有誰是master的信息,讀取哨兵的配置文件,獲取ip地址和端口號(hào),與哨兵建立連接,連接之后訂閱信息,獲取主庫信息,并與主庫建立連接
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Redis監(jiān)控工具RedisInsight安裝與使用
這篇文章主要為大家介紹了Redis監(jiān)控工具RedisInsight的安裝步驟與使用方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03
小白也能看懂的Redis遍歷鍵和數(shù)據(jù)庫管理詳解
這篇文章主要為大家介紹了小白也能看懂的Redis遍歷鍵和數(shù)據(jù)庫管理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
RedisDesktopManager遠(yuǎn)程連接redis的實(shí)現(xiàn)
本文主要介紹了RedisDesktopManager遠(yuǎn)程連接redis的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
Redis基礎(chǔ)學(xué)習(xí)之管道機(jī)制詳析
這篇文章主要給大家介紹了關(guān)于Redis基礎(chǔ)學(xué)習(xí)之管道機(jī)制的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Redis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11
基于Redis實(shí)現(xiàn)共享Session登錄的實(shí)現(xiàn)
本文主要介紹了基于Redis實(shí)現(xiàn)共享Session登錄的實(shí)現(xiàn),包括發(fā)送短信驗(yàn)證碼、短信驗(yàn)證碼登錄和注冊(cè)、以及登錄狀態(tài)校驗(yàn)的流程,具有一定的參考價(jià)值,感興趣的可以了解一下2025-03-03

