我們知道主從復(fù)制是高可用的基石说榆,從庫宕機(jī)依然可以將請求發(fā)送給主庫或者其他從庫,但是 Master 宕機(jī)牛郑,只能響應(yīng)讀操作怠肋,寫請求無法再執(zhí)行。
所以主從復(fù)制架構(gòu)面臨一個嚴(yán)峻問題淹朋,主庫掛了笙各,無法執(zhí)行「寫操作」,無法自動選擇一個 Slave 切換為 Master础芍,也就是無法故障自動切換杈抢。
什么是哨兵(Sentinel)
搭建實(shí)例采用三個哨兵形成集群,三個數(shù)據(jù)節(jié)點(diǎn)(一主兩從)方式搭建仑性,如下圖所示:
哨兵機(jī)制的主要任務(wù)
哨兵是 Redis 的一種運(yùn)行模式惶楼,它專注于對 Redis 實(shí)例(主節(jié)點(diǎn)、從節(jié)點(diǎn))運(yùn)行狀態(tài)的監(jiān)控诊杆,并能夠在主節(jié)點(diǎn)發(fā)生故障時通過一系列的機(jī)制實(shí)現(xiàn)選主及主從切換歼捐,實(shí)現(xiàn)故障轉(zhuǎn)移,確保整個 Redis 系統(tǒng)的可用性晨汹。結(jié)合 Redis 的 官方文檔:https://redis.io/topics/sentinel豹储,可以知道 Redis 哨兵具備的能力有如下幾個:
- 監(jiān)控:持續(xù)監(jiān)控 master 、slave 是否處于預(yù)期工作狀態(tài)淘这。
- 自動切換主庫:當(dāng) Master 運(yùn)行故障剥扣,哨兵啟動自動故障恢復(fù)流程:從 slave 中選擇一臺作為新 master巩剖。
- 通知:讓 slave 執(zhí)行 replicaof ,與新的 master 同步钠怯;并且通知客戶端與新 master 建立連接球及。
監(jiān)控
在默認(rèn)情況下,Sentinel 通過以每秒一次的頻率向所有包括 Master呻疹、Slave、其他 Sentinel 在內(nèi))發(fā)送 PING 命令筹陵,如果 slave 沒有在在規(guī)定時間內(nèi)響應(yīng)「哨兵」的 PING 命令刽锤,「哨兵」就認(rèn)為這哥們可能嗝屁了,就會將他記錄為「下線狀態(tài)」朦佩;
假如 master 沒有在規(guī)定時間響應(yīng) 「哨兵」的 PING 命令并思,哨兵就判定master下線,開始執(zhí)行「自動切換 master 」的流程语稠。
PING 命令的回復(fù)有兩種情況:
有效回復(fù):返回 +PONG宋彼、-LOADING、-MASTERDOWN 任何一種仙畦;
無效回復(fù):有效回復(fù)之外的回復(fù)输涕,或者指定時間內(nèi)返回任何回復(fù)。
為了防止master「假死」慨畸,「哨兵」設(shè)計了「主觀下線」和「客觀下線」兩種暗號莱坎。
主觀下線
哨兵利用 PING 命令來檢測master、 slave 的生命狀態(tài)寸士。如果是無效回復(fù)檐什,哨兵就把這個哥們標(biāo)記為「主觀下線」。
因為有可能出現(xiàn)誤判弱卡,master并沒有嗝屁乃正,一旦啟動了master切換,后續(xù)的選主婶博、通知瓮具,slave 花時間與新 master 同步數(shù)據(jù)都會消耗大量資源。
所以「哨兵」要降低誤判的概率凡蜻,誤判一般會發(fā)生在集群網(wǎng)絡(luò)壓力較大搭综、網(wǎng)絡(luò)擁塞,或者是主庫本身壓力較大的情況下划栓。
既然一個人容易誤判兑巾,那就多個人一起投票判斷。哨兵機(jī)制也是類似的忠荞,采用多實(shí)例組成的集群模式進(jìn)行部署蒋歌,這就是哨兵集群帅掘。引入多個哨兵實(shí)例一起來判斷,就可以避免單個哨兵因為自身網(wǎng)絡(luò)狀況不好堂油,而誤判主庫下線的情況修档。
同時,多個哨兵的網(wǎng)絡(luò)同時不穩(wěn)定的概率較小府框,由它們一起做決策吱窝,誤判率也能降低。
客觀下線
判斷 master 是否下線不能只有一個「哨兵」說了算迫靖,只有過半的哨兵判斷 master 已經(jīng)「主觀下線」院峡,這時候才能將 master 標(biāo)記為「客觀下線」,也就是說這是一個客觀事實(shí)系宜。
主觀下線與客觀下線的區(qū)別
簡單來說照激,主觀下線是哨兵自己認(rèn)為節(jié)點(diǎn)宕機(jī),而客觀下線是不但哨兵自己認(rèn)為節(jié)點(diǎn)宕機(jī)盹牧,而且該哨兵與其他哨兵溝通后俩垃,達(dá)到一定數(shù)量的哨兵都認(rèn)為該哥們嗝屁了。
這里的「一定數(shù)量」是一個法定數(shù)量(Quorum)汰寓,是由哨兵監(jiān)控配置決定的口柳,解釋一下該配置:
這條配置項用于告知哨兵需要監(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ù)量辣卒,代表只有兩個或兩個以上的哨兵認(rèn)為主節(jié)點(diǎn)不可用的時候,才會把 master 設(shè)置為客觀下線狀態(tài)睛榄,然后進(jìn)行 failover 操作荣茫。
「客觀下線」的標(biāo)準(zhǔn)就是,當(dāng)有 N 個哨兵實(shí)例時场靴,要有 N/2 + 1 個實(shí)例判斷 master 為「主觀下線」啡莉,才能最終判定 Master 為「客觀下線」,其實(shí)就是過半機(jī)制旨剥。
自動切換主庫
「哨兵」的第二個任務(wù)咧欣,選擇新 master 。按照一定的 「篩選條件」 + 「打分」 策略轨帜,將得分最高者選為新 master魄咕。
篩選條件
- 從庫當(dāng)前在線狀態(tài),下線的直接丟棄蚌父;
- 評估之前的網(wǎng)絡(luò)連接狀態(tài) down-after-milliseconds * 10:如果從庫總是和主庫斷連哮兰,而且斷連次數(shù)超出了一定的閾值(10 次)毛萌,我們就有理由相信,這個從庫的網(wǎng)絡(luò)狀況并不是太好喝滞,就可以把這個從庫篩掉了阁将。
打分
過濾掉不合適的 slave 之后,則進(jìn)入打分環(huán)節(jié)右遭。打分會按照三個規(guī)則進(jìn)行三輪打分做盅,規(guī)則分別為:
1、slave 優(yōu)先級窘哈,通過 slave-priority 配置項言蛇,給不同的從庫設(shè)置不同優(yōu)先級(后臺有人沒辦法),優(yōu)先級高的直接晉級為新 master 宵距。
2、slave_repl_offset與 master_repl_offset進(jìn)度差距吨拗,如果都一樣满哪,那就繼續(xù)下一個規(guī)則。其實(shí)就是比較 slave 與舊 master 復(fù)制進(jìn)度的差距劝篷;
3哨鸭、slave runID,在優(yōu)先級和復(fù)制進(jìn)度都相同的情況下娇妓,ID 號最小的從庫得分最高像鸡,會被選為新主庫。(論資排輩哈恰,根據(jù) runID 的創(chuàng)建時間來判斷只估,時間早的上位);
通知
哨兵集群工作原理
「哨兵」并不是一個人着绷,多個人共同組成一個「哨兵集群」蛔钙,即使有一些「哨兵」被老王打死了,其他的「哨兵」依然可以共同協(xié)作完成監(jiān)控荠医、選舉以及通知 slave 吁脱、master 以及客戶端。
在配置哨兵集群的時候彬向,哨兵配置中只設(shè)置了監(jiān)控的 master IP 和 port兼贡,并沒有配置其他哨兵的連接信息。
哨兵之間是如何知道彼此的娃胆?如何知道 slave 并監(jiān)控他們的遍希?由哪一個「哨兵」執(zhí)行主從切換呢?
pub/sub 實(shí)現(xiàn)哨兵間通信和發(fā)現(xiàn) slave
哨兵之間可以相互通信搞事情里烦,主要?dú)w功于 Redis 的 pub/sub 發(fā)布/訂閱機(jī)制孵班。
哨兵與 master 建立通信涉兽,利用 master 提供發(fā)布/訂閱機(jī)制發(fā)布自己的信息,比如身高體重篙程、是否單身枷畏、IP、端口……
master 有一個 sentinel:hello 的專用通道虱饿,用于哨兵之間發(fā)布和訂閱消息拥诡。這就好比是 sentinel:hello 微信群,哨兵利用 master 建立的微信群發(fā)布自己的消息氮发,同時關(guān)注其他哨兵發(fā)布的消息渴肉。
當(dāng)多個哨兵實(shí)例都在主庫上做了發(fā)布和訂閱操作后,它們之間就能知道彼此的 IP 地址和端口爽冕,從而相互發(fā)現(xiàn)建立連接仇祭。
Redis 通過頻道的方式對消息進(jìn)行分別管理,這里的頻道其實(shí)就是不同的微信群颈畸。
哨兵之間雖然建立連接了乌奇,但是還需要和 slave 建立連接,不然沒法監(jiān)控他們呀眯娱,如何知道 slave 并監(jiān)控他們的礁苗?
關(guān)鍵還是利用 master 來實(shí)現(xiàn),哨兵向 master 發(fā)送 INFO 命令徙缴, master 自然是知道所有的 salve的试伙。所以 master 接收到命令后,便將 slave 列表告訴哨兵于样。
哨兵根據(jù) master 響應(yīng)的 slave 名單信息與每一個 salve 建立連接疏叨,并且根據(jù)這個連接持續(xù)監(jiān)控哨兵。
選擇哨兵執(zhí)行主從切換
這個跟哨兵判斷 master “客觀下線”類似穿剖,也是通過投票的方式選出來的考廉。
任何一個哨兵判斷 master “主觀下線”后,就會給其他哨兵基友發(fā)送 is-master-down-by-addr 命令携御,好基友則根據(jù)自己跟 master 之間的連接狀況分別響應(yīng) Y 或者 N 昌粤,Y 表示贊成票, N 就是反對啄刹。
如果某個哨兵獲得了大多數(shù)哨兵的“贊成票”之后涮坐,就可以標(biāo)記 master 為 “客觀下線”,贊成票數(shù)是通過哨兵配置文件中的 quorum 配置項設(shè)定誓军。
獲得多數(shù)贊成票的哨兵可以向其他哨兵發(fā)送命令袱讹,申明自己想要執(zhí)行主從切換。并讓其他哨兵進(jìn)行投票,投票過程就叫做 “Leader 選舉”捷雕。
想要成為 “Leader”沒那么簡單椒丧,得有兩把刷子。需要滿足以下條件:
1救巷、獲得其他哨兵基友過半的贊成票壶熏;
2、贊成票的數(shù)量還要大于等于配置文件的 quorum 的值浦译。
通過 pub/sub 實(shí)現(xiàn)客戶端事件通知
新 master 選出來了棒假,要怎么公示天下呢?
在 Redis 也是類似精盅,通過 pub/sub 機(jī)制發(fā)布不同事件帽哑,讓客戶端在這里訂閱消息√厩危客戶端可以訂閱哨兵的消息妻枕,哨兵提供的消息訂閱頻道有很多,不同頻道包含了主從庫切換過程中的不同關(guān)鍵事件粘驰。
也就是在不同的“微信群”發(fā)布不同的事件屡谐,讓對該事件感興趣的人進(jìn)群即可。