Redis哨兵模式高可用原理

我們知道主從復(fù)制是高可用的基石,從庫(kù)宕機(jī)依然可以將請(qǐng)求發(fā)送給主庫(kù)或者其他從庫(kù),但是 Master 宕機(jī),只能響應(yīng)讀操作,寫請(qǐng)求無(wú)法再執(zhí)行。

所以主從復(fù)制架構(gòu)面臨一個(gè)嚴(yán)峻問題,主庫(kù)掛了,無(wú)法執(zhí)行「寫操作」,無(wú)法自動(dòng)選擇一個(gè) Slave 切換為 Master,也就是無(wú)法故障自動(dòng)切換。

什么是哨兵(Sentinel)

搭建實(shí)例采用三個(gè)哨兵形成集群,三個(gè)數(shù)據(jù)節(jié)點(diǎn)(一主兩從)方式搭建,如下圖所示:

哨兵機(jī)制的主要任務(wù)

哨兵是 Redis 的一種運(yùn)行模式,它專注于對(duì) Redis 實(shí)例(主節(jié)點(diǎn)、從節(jié)點(diǎn))運(yùn)行狀態(tài)的監(jiān)控,并能夠在主節(jié)點(diǎn)發(fā)生故障時(shí)通過(guò)一系列的機(jī)制實(shí)現(xiàn)選主及主從切換,實(shí)現(xiàn)故障轉(zhuǎn)移,確保整個(gè) Redis 系統(tǒng)的可用性。結(jié)合 Redis 的 官方文檔:https://redis.io/topics/sentinel,可以知道 Redis 哨兵具備的能力有如下幾個(gè):

  • 監(jiān)控:持續(xù)監(jiān)控 master 、slave 是否處于預(yù)期工作狀態(tài)。
  • 自動(dòng)切換主庫(kù):當(dāng) Master 運(yùn)行故障,哨兵啟動(dòng)自動(dòng)故障恢復(fù)流程:從 slave 中選擇一臺(tái)作為新 master。
  • 通知:讓 slave 執(zhí)行 replicaof ,與新的 master 同步;并且通知客戶端與新 master 建立連接。

監(jiān)控

在默認(rèn)情況下,Sentinel 通過(guò)以每秒一次的頻率向所有包括 Master、Slave、其他 Sentinel 在內(nèi))發(fā)送 PING 命令,如果 slave 沒有在在規(guī)定時(shí)間內(nèi)響應(yīng)「哨兵」的 PING 命令,「哨兵」就認(rèn)為這哥們可能嗝屁了,就會(huì)將他記錄為「下線狀態(tài)」;

假如 master 沒有在規(guī)定時(shí)間響應(yīng) 「哨兵」的 PING 命令,哨兵就判定master下線,開始執(zhí)行「自動(dòng)切換 master 」的流程。

PING 命令的回復(fù)有兩種情況:

有效回復(fù):返回 +PONG、-LOADING、-MASTERDOWN 任何一種;
無(wú)效回復(fù):有效回復(fù)之外的回復(fù),或者指定時(shí)間內(nèi)返回任何回復(fù)。

為了防止master「假死」,「哨兵」設(shè)計(jì)了「主觀下線」和「客觀下線」兩種暗號(hào)。

主觀下線
哨兵利用 PING 命令來(lái)檢測(cè)master、 slave 的生命狀態(tài)。如果是無(wú)效回復(fù),哨兵就把這個(gè)哥們標(biāo)記為「主觀下線」。

因?yàn)橛锌赡艹霈F(xiàn)誤判,master并沒有嗝屁,一旦啟動(dòng)了master切換,后續(xù)的選主、通知,slave 花時(shí)間與新 master 同步數(shù)據(jù)都會(huì)消耗大量資源。

所以「哨兵」要降低誤判的概率,誤判一般會(huì)發(fā)生在集群網(wǎng)絡(luò)壓力較大、網(wǎng)絡(luò)擁塞,或者是主庫(kù)本身壓力較大的情況下。

既然一個(gè)人容易誤判,那就多個(gè)人一起投票判斷。哨兵機(jī)制也是類似的,采用多實(shí)例組成的集群模式進(jìn)行部署,這就是哨兵集群。引入多個(gè)哨兵實(shí)例一起來(lái)判斷,就可以避免單個(gè)哨兵因?yàn)樽陨砭W(wǎng)絡(luò)狀況不好,而誤判主庫(kù)下線的情況。

同時(shí),多個(gè)哨兵的網(wǎng)絡(luò)同時(shí)不穩(wěn)定的概率較小,由它們一起做決策,誤判率也能降低。

客觀下線
判斷 master 是否下線不能只有一個(gè)「哨兵」說(shuō)了算,只有過(guò)半的哨兵判斷 master 已經(jīng)「主觀下線」,這時(shí)候才能將 master 標(biāo)記為「客觀下線」,也就是說(shuō)這是一個(gè)客觀事實(shí)。

主觀下線與客觀下線的區(qū)別
簡(jiǎn)單來(lái)說(shuō),主觀下線是哨兵自己認(rèn)為節(jié)點(diǎn)宕機(jī),而客觀下線是不但哨兵自己認(rèn)為節(jié)點(diǎn)宕機(jī),而且該哨兵與其他哨兵溝通后,達(dá)到一定數(shù)量的哨兵都認(rèn)為該哥們嗝屁了。

這里的「一定數(shù)量」是一個(gè)法定數(shù)量(Quorum),是由哨兵監(jiān)控配置決定的,解釋一下該配置:



這條配置項(xiàng)用于告知哨兵需要監(jiān)聽的主節(jié)點(diǎn):

  • sentinel monitor:代表監(jiān)控。
  • mymaster:代表主節(jié)點(diǎn)的名稱,可以自定義。
  • 192.168.11.128:代表監(jiān)控的主節(jié)點(diǎn) ip,6379 代表端口。
  • 2:法定數(shù)量,代表只有兩個(gè)或兩個(gè)以上的哨兵認(rèn)為主節(jié)點(diǎn)不可用的時(shí)候,才會(huì)把 master 設(shè)置為客觀下線狀態(tài),然后進(jìn)行 failover 操作。

「客觀下線」的標(biāo)準(zhǔn)就是,當(dāng)有 N 個(gè)哨兵實(shí)例時(shí),要有 N/2 + 1 個(gè)實(shí)例判斷 master 為「主觀下線」,才能最終判定 Master 為「客觀下線」,其實(shí)就是過(guò)半機(jī)制。

自動(dòng)切換主庫(kù)

「哨兵」的第二個(gè)任務(wù),選擇新 master 。按照一定的 「篩選條件」 + 「打分」 策略,將得分最高者選為新 master。


篩選條件

  • 從庫(kù)當(dāng)前在線狀態(tài),下線的直接丟棄;
  • 評(píng)估之前的網(wǎng)絡(luò)連接狀態(tài) down-after-milliseconds * 10:如果從庫(kù)總是和主庫(kù)斷連,而且斷連次數(shù)超出了一定的閾值(10 次),我們就有理由相信,這個(gè)從庫(kù)的網(wǎng)絡(luò)狀況并不是太好,就可以把這個(gè)從庫(kù)篩掉了。

打分
過(guò)濾掉不合適的 slave 之后,則進(jìn)入打分環(huán)節(jié)。打分會(huì)按照三個(gè)規(guī)則進(jìn)行三輪打分,規(guī)則分別為:
1、slave 優(yōu)先級(jí),通過(guò) slave-priority 配置項(xiàng),給不同的從庫(kù)設(shè)置不同優(yōu)先級(jí)(后臺(tái)有人沒辦法),優(yōu)先級(jí)高的直接晉級(jí)為新 master 。
2、slave_repl_offset與 master_repl_offset進(jìn)度差距,如果都一樣,那就繼續(xù)下一個(gè)規(guī)則。其實(shí)就是比較 slave 與舊 master 復(fù)制進(jìn)度的差距;
3、slave runID,在優(yōu)先級(jí)和復(fù)制進(jìn)度都相同的情況下,ID 號(hào)最小的從庫(kù)得分最高,會(huì)被選為新主庫(kù)。(論資排輩,根據(jù) runID 的創(chuàng)建時(shí)間來(lái)判斷,時(shí)間早的上位);

通知

哨兵集群工作原理

「哨兵」并不是一個(gè)人,多個(gè)人共同組成一個(gè)「哨兵集群」,即使有一些「哨兵」被老王打死了,其他的「哨兵」依然可以共同協(xié)作完成監(jiān)控、選舉以及通知 slave 、master 以及客戶端。

在配置哨兵集群的時(shí)候,哨兵配置中只設(shè)置了監(jiān)控的 master IP 和 port,并沒有配置其他哨兵的連接信息。

哨兵之間是如何知道彼此的?如何知道 slave 并監(jiān)控他們的?由哪一個(gè)「哨兵」執(zhí)行主從切換呢?

pub/sub 實(shí)現(xiàn)哨兵間通信和發(fā)現(xiàn) slave

哨兵之間可以相互通信搞事情,主要?dú)w功于 Redis 的 pub/sub 發(fā)布/訂閱機(jī)制。

哨兵與 master 建立通信,利用 master 提供發(fā)布/訂閱機(jī)制發(fā)布自己的信息,比如身高體重、是否單身、IP、端口……

master 有一個(gè) sentinel:hello 的專用通道,用于哨兵之間發(fā)布和訂閱消息。這就好比是 sentinel:hello 微信群,哨兵利用 master 建立的微信群發(fā)布自己的消息,同時(shí)關(guān)注其他哨兵發(fā)布的消息。

當(dāng)多個(gè)哨兵實(shí)例都在主庫(kù)上做了發(fā)布和訂閱操作后,它們之間就能知道彼此的 IP 地址和端口,從而相互發(fā)現(xiàn)建立連接。

Redis 通過(guò)頻道的方式對(duì)消息進(jìn)行分別管理,這里的頻道其實(shí)就是不同的微信群。

哨兵之間雖然建立連接了,但是還需要和 slave 建立連接,不然沒法監(jiān)控他們呀,如何知道 slave 并監(jiān)控他們的?

關(guān)鍵還是利用 master 來(lái)實(shí)現(xiàn),哨兵向 master 發(fā)送 INFO 命令, master 自然是知道所有的 salve的。所以 master 接收到命令后,便將 slave 列表告訴哨兵。

哨兵根據(jù) master 響應(yīng)的 slave 名單信息與每一個(gè) salve 建立連接,并且根據(jù)這個(gè)連接持續(xù)監(jiān)控哨兵。

選擇哨兵執(zhí)行主從切換

這個(gè)跟哨兵判斷 master “客觀下線”類似,也是通過(guò)投票的方式選出來(lái)的。

任何一個(gè)哨兵判斷 master “主觀下線”后,就會(huì)給其他哨兵基友發(fā)送 is-master-down-by-addr 命令,好基友則根據(jù)自己跟 master 之間的連接狀況分別響應(yīng) Y 或者 N ,Y 表示贊成票, N 就是反對(duì)。

如果某個(gè)哨兵獲得了大多數(shù)哨兵的“贊成票”之后,就可以標(biāo)記 master 為 “客觀下線”,贊成票數(shù)是通過(guò)哨兵配置文件中的 quorum 配置項(xiàng)設(shè)定。

獲得多數(shù)贊成票的哨兵可以向其他哨兵發(fā)送命令,申明自己想要執(zhí)行主從切換。并讓其他哨兵進(jìn)行投票,投票過(guò)程就叫做 “Leader 選舉”。

想要成為 “Leader”沒那么簡(jiǎn)單,得有兩把刷子。需要滿足以下條件:

1、獲得其他哨兵基友過(guò)半的贊成票;
2、贊成票的數(shù)量還要大于等于配置文件的 quorum 的值。

通過(guò) pub/sub 實(shí)現(xiàn)客戶端事件通知

新 master 選出來(lái)了,要怎么公示天下呢?

在 Redis 也是類似,通過(guò) pub/sub 機(jī)制發(fā)布不同事件,讓客戶端在這里訂閱消息。客戶端可以訂閱哨兵的消息,哨兵提供的消息訂閱頻道有很多,不同頻道包含了主從庫(kù)切換過(guò)程中的不同關(guān)鍵事件。

也就是在不同的“微信群”發(fā)布不同的事件,讓對(duì)該事件感興趣的人進(jìn)群即可。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容