Redis哨兵模式高可用原理

我們知道主從複製是高可用的基石,從庫宕機依然可以將請求發送給主庫或者其他從庫,但是 Master 宕機,只能響應讀操作,寫請求無法再執行。

所以主從複製架構面臨一個嚴峻問題,主庫掛了,無法執行「寫操作」,無法自動選擇一個 Slave 切換爲 Master,也就是無法故障自動切換。

什麼是哨兵(Sentinel)

搭建實例採用三個哨兵形成集羣,三個數據節點(一主兩從)方式搭建,如下圖所示:

哨兵機制的主要任務

哨兵是 Redis 的一種運行模式,它專注於對 Redis 實例(主節點、從節點)運行狀態的監控,並能夠在主節點發生故障時通過一系列的機制實現選主及主從切換,實現故障轉移,確保整個 Redis 系統的可用性。結合 Redis 的 官方文檔:https://redis.io/topics/sentinel,可以知道 Redis 哨兵具備的能力有如下幾個:

  • 監控:持續監控 master 、slave 是否處於預期工作狀態。
  • 自動切換主庫:當 Master 運行故障,哨兵啓動自動故障恢復流程:從 slave 中選擇一臺作爲新 master。
  • 通知:讓 slave 執行 replicaof ,與新的 master 同步;並且通知客戶端與新 master 建立連接。

監控

在默認情況下,Sentinel 通過以每秒一次的頻率向所有包括 Master、Slave、其他 Sentinel 在內)發送 PING 命令,如果 slave 沒有在在規定時間內響應「哨兵」的 PING 命令,「哨兵」就認爲這哥們可能嗝屁了,就會將他記錄爲「下線狀態」;

假如 master 沒有在規定時間響應 「哨兵」的 PING 命令,哨兵就判定master下線,開始執行「自動切換 master 」的流程。

PING 命令的回覆有兩種情況:

有效回覆:返回 +PONG、-LOADING、-MASTERDOWN 任何一種;
無效回覆:有效回覆之外的回覆,或者指定時間內返回任何回覆。

爲了防止master「假死」,「哨兵」設計了「主觀下線」和「客觀下線」兩種暗號。

主觀下線
哨兵利用 PING 命令來檢測master、 slave 的生命狀態。如果是無效回覆,哨兵就把這個哥們標記爲「主觀下線」。

因爲有可能出現誤判,master並沒有嗝屁,一旦啓動了master切換,後續的選主、通知,slave 花時間與新 master 同步數據都會消耗大量資源。

所以「哨兵」要降低誤判的概率,誤判一般會發生在集羣網絡壓力較大、網絡擁塞,或者是主庫本身壓力較大的情況下。

既然一個人容易誤判,那就多個人一起投票判斷。哨兵機制也是類似的,採用多實例組成的集羣模式進行部署,這就是哨兵集羣。引入多個哨兵實例一起來判斷,就可以避免單個哨兵因爲自身網絡狀況不好,而誤判主庫下線的情況。

同時,多個哨兵的網絡同時不穩定的概率較小,由它們一起做決策,誤判率也能降低。

客觀下線
判斷 master 是否下線不能只有一個「哨兵」說了算,只有過半的哨兵判斷 master 已經「主觀下線」,這時候才能將 master 標記爲「客觀下線」,也就是說這是一個客觀事實。

主觀下線與客觀下線的區別
簡單來說,主觀下線是哨兵自己認爲節點宕機,而客觀下線是不但哨兵自己認爲節點宕機,而且該哨兵與其他哨兵溝通後,達到一定數量的哨兵都認爲該哥們嗝屁了。

這裏的「一定數量」是一個法定數量(Quorum),是由哨兵監控配置決定的,解釋一下該配置:



這條配置項用於告知哨兵需要監聽的主節點:

  • sentinel monitor:代表監控。
  • mymaster:代表主節點的名稱,可以自定義。
  • 192.168.11.128:代表監控的主節點 ip,6379 代表端口。
  • 2:法定數量,代表只有兩個或兩個以上的哨兵認爲主節點不可用的時候,纔會把 master 設置爲客觀下線狀態,然後進行 failover 操作。

「客觀下線」的標準就是,當有 N 個哨兵實例時,要有 N/2 + 1 個實例判斷 master 爲「主觀下線」,才能最終判定 Master 爲「客觀下線」,其實就是過半機制。

自動切換主庫

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


篩選條件

  • 從庫當前在線狀態,下線的直接丟棄;
  • 評估之前的網絡連接狀態 down-after-milliseconds * 10:如果從庫總是和主庫斷連,而且斷連次數超出了一定的閾值(10 次),我們就有理由相信,這個從庫的網絡狀況並不是太好,就可以把這個從庫篩掉了。

打分
過濾掉不合適的 slave 之後,則進入打分環節。打分會按照三個規則進行三輪打分,規則分別爲:
1、slave 優先級,通過 slave-priority 配置項,給不同的從庫設置不同優先級(後臺有人沒辦法),優先級高的直接晉級爲新 master 。
2、slave_repl_offset與 master_repl_offset進度差距,如果都一樣,那就繼續下一個規則。其實就是比較 slave 與舊 master 複製進度的差距;
3、slave runID,在優先級和複製進度都相同的情況下,ID 號最小的從庫得分最高,會被選爲新主庫。(論資排輩,根據 runID 的創建時間來判斷,時間早的上位);

通知

哨兵集羣工作原理

「哨兵」並不是一個人,多個人共同組成一個「哨兵集羣」,即使有一些「哨兵」被老王打死了,其他的「哨兵」依然可以共同協作完成監控、選舉以及通知 slave 、master 以及客戶端。

在配置哨兵集羣的時候,哨兵配置中只設置了監控的 master IP 和 port,並沒有配置其他哨兵的連接信息。

哨兵之間是如何知道彼此的?如何知道 slave 並監控他們的?由哪一個「哨兵」執行主從切換呢?

pub/sub 實現哨兵間通信和發現 slave

哨兵之間可以相互通信搞事情,主要歸功於 Redis 的 pub/sub 發佈/訂閱機制。

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

master 有一個 sentinel:hello 的專用通道,用於哨兵之間發佈和訂閱消息。這就好比是 sentinel:hello 微信羣,哨兵利用 master 建立的微信羣發佈自己的消息,同時關注其他哨兵發佈的消息。

當多個哨兵實例都在主庫上做了發佈和訂閱操作後,它們之間就能知道彼此的 IP 地址和端口,從而相互發現建立連接。

Redis 通過頻道的方式對消息進行分別管理,這裏的頻道其實就是不同的微信羣。

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

關鍵還是利用 master 來實現,哨兵向 master 發送 INFO 命令, master 自然是知道所有的 salve的。所以 master 接收到命令後,便將 slave 列表告訴哨兵。

哨兵根據 master 響應的 slave 名單信息與每一個 salve 建立連接,並且根據這個連接持續監控哨兵。

選擇哨兵執行主從切換

這個跟哨兵判斷 master “客觀下線”類似,也是通過投票的方式選出來的。

任何一個哨兵判斷 master “主觀下線”後,就會給其他哨兵基友發送 is-master-down-by-addr 命令,好基友則根據自己跟 master 之間的連接狀況分別響應 Y 或者 N ,Y 表示贊成票, N 就是反對。

如果某個哨兵獲得了大多數哨兵的“贊成票”之後,就可以標記 master 爲 “客觀下線”,贊成票數是通過哨兵配置文件中的 quorum 配置項設定。

獲得多數贊成票的哨兵可以向其他哨兵發送命令,申明自己想要執行主從切換。並讓其他哨兵進行投票,投票過程就叫做 “Leader 選舉”。

想要成爲 “Leader”沒那麼簡單,得有兩把刷子。需要滿足以下條件:

1、獲得其他哨兵基友過半的贊成票;
2、贊成票的數量還要大於等於配置文件的 quorum 的值。

通過 pub/sub 實現客戶端事件通知

新 master 選出來了,要怎麼公示天下呢?

在 Redis 也是類似,通過 pub/sub 機制發佈不同事件,讓客戶端在這裏訂閱消息。客戶端可以訂閱哨兵的消息,哨兵提供的消息訂閱頻道有很多,不同頻道包含了主從庫切換過程中的不同關鍵事件。

也就是在不同的“微信羣”發佈不同的事件,讓對該事件感興趣的人進羣即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章