Redis 高可用篇:你管這叫 Sentinel 哨兵集羣原理

概要

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

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

深夜與女朋友麼麼噠……(此處省略 10000 字),突然宕機,總不能提起褲子從牀上爬起來手工進行主從切換,再通知其他程序員把地址重新改成新主庫上線

如此一折騰自己已被女友切換成前男友了,萬萬使不得。所以我們必須有一個高可用的方案,爲此,Redis 官方提供一個高可用方案——哨兵(Sentinel)

Redis 哨兵集羣原理

開篇寄語

技術的迭代非常的快,但是從技術中沉澱下來的思維卻是受益終生的。所以不要擔心什麼中年危機,那些擔心中年危機的人通常很難成長起來。只要我們成長,只要我們的認知在不斷突破,就不用擔心中年危機,這個世界始終是需要那些優秀人才的。

什麼是哨兵(Sentinel)

65 哥:碼哥,雖然我沒女朋友,但是,未雨綢繆我要掌握這個哨兵模式,防止當深夜與女朋友麼麼噠被打擾,你快說說哨兵的實現原理吧。

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

Redis哨兵集羣

哨兵集羣的搭建演示就不在這裏贅述了,需要的讀者朋友可點擊左下角的「閱讀原文」查看。

65 哥你聽過「武當派」創始人張三瘋麼?Redis 主從架構就好比一個武當,掌門人就是 Master。掌門人如果掛了,需要從武當七俠裏面選舉能人擔當掌門人。這就需要一個部門能監控掌門人的生死和武當其他弟子的生命狀態,並且能夠通過投票從武當弟子中選舉一個能者擔任新掌門,接着再舉行新聞發佈會向世界宣佈新掌門的信息。這個「部門」就是哨兵。

哨兵在選舉新掌門會遇到以下幾個問題:

  1. 如何判斷掌門真的掛了,有可能假死;
  2. 到底選擇哪一個武當子弟作爲新掌門?
  3. 通過新聞發佈會將新掌門的相關信息通知到所有武當弟子(slave 和 master)和整個武林(客戶端)

哨兵部門主要負責的任務是:監控整個武當、選擇新掌門,通知整個武當和整個武林。

哨兵機制的主要任務

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

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

哨兵也是一個 Redis 進程,只是不對外提供讀寫服務,通常哨兵要配置成單數,爲啥呢?且聽「碼哥字節」慢慢分析。

65 哥:那到底「哨兵」這個神祕部門是如何實現這三個能力的?

我們先從全局觀看哨兵,簡要的瞭解整個運作流程,接着再針對每一個任務詳細分析。首先從監控開始…...

監控

Sentinel 只是武當弟子中的特殊部門,在默認情況下,Sentinel 通過飛鴿傳書以每秒一次的頻率向所有武當弟子、掌門與哨兵(包括 Master、Slave、其他 Sentinel 在內)發送 PING 命令,如果 slave 沒有在在規定時間內響應「哨兵」的 PING 命令,「哨兵」就認爲這哥們可能嗝屁了,就會將他記錄爲「下線狀態」;

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

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

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

65 哥:哨兵如何判斷「掌門」嗝屁呢?掌門詐屍咋辦?

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

主觀下線

哨兵利用 PING 命令來檢測掌門、 slave 的生命狀態。如果是無效回覆,哨兵就把這個哥們標記爲「主觀下線」。檢測到的是武當小弟,也就是 slave 角色。那麼就直接標記「主觀下線」。

因爲 master 掌門還在,slave 的嗝屁對整個武當影響不大。依然可以對外開會,比武論劍、喫香喝辣…...

如果檢測到是 master 掌門完蛋,這時候哨兵不能這麼簡單的標記「主觀下線」,開啓新掌門選舉。

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

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

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

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

客觀下線

判斷 master 是否下線不能只有一個「哨兵」說了算,只有過半的哨兵判斷 master 已經「主觀下線」,這時候才能將 master 標記爲「客觀下線」,也就是說這是一個客觀事實,掌門真的嗝屁了,華佗再世也治不好了。

只有 master 被判定爲「客觀下線」,纔會進一步觸發哨兵開始主從切換流程。

客觀下線

主觀下線與客觀下線的區別

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

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

# sentinel monitor <master-name> <master-host> <master-port> <quorum>
# 舉例如下:
sentinel monitor mymaster 127.0.0.1 6379 2

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

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

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

自動切換主庫

65 哥:既然判斷 master 客觀下線了,那就要從選出一個新掌門人了吧。

「哨兵」的第二個任務,選擇新 master 掌門。需要從武當弟子中按照一定規則選擇一個牛逼人物作爲新掌門,完成選任掌門後,新 master 帶領衆弟子一起喫香喝辣。

按照一定的「篩選條件」 + 「打分」策略,選出「最強王者」擔任掌門,也就是通過一些條件海選過濾一些「無能之輩」,接着將通過海選的靚仔全都打分排名,將最高者選爲新 master。

如圖所示:

新master選擇

網絡經常斷開的靚仔也不可取,你想,即使變成 master,可是很快網絡出了故障,又得重新選擇新 master,這不鬧着玩麼,得排除掉!

篩選條件

65 哥:那都有哪些篩選條件呀?

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

打分

過濾掉不合適的 slave 之後,則進入打分環節。打分會按照三個規則進行三輪打分,規則分別爲:

  1. slave 優先級,通過 slave-priority 配置項,給不同的從庫設置不同優先級(後臺有人沒辦法),優先級高的直接晉級爲新 master 掌門。
  2. slave_repl_offsetmaster_repl_offset進度差距(誰的武功與之前掌門的功夫越接近誰就更牛逼),如果都一樣,那就繼續下一個規則。其實就是比較 slave 與舊 master 複製進度的差距;
  3. slave runID,在優先級和複製進度都相同的情況下,ID 號最小的從庫得分最高,會被選爲新主庫。 (論資排輩,根據 runID 的創建時間來判斷,時間早的上位);

通知

65 哥:爲哈還要召開新聞發佈會呢?

重新選舉新 master 掌門這種事情,何等大事,怎能不告知天下。再者其他 slave 弟子也要知道新掌門是誰,一起追隨新掌門喫香喝辣大保健。

最後一個任務,「哨兵」將新 「master 掌門」的連接信息發送給其他 slave 武當弟子,並且讓 slave 執行 replacaof 命令,和新「master 掌門」建立連接,並進行數據複製學習新掌門的所有武功。

除此之外,「哨兵」還需要將新掌門的連接信息通知整個武林(客戶端),使得讓所有想拜訪、討教的人能找到新任掌門,這樣諸多事宜才能交給新掌門做決定(將讀寫請求轉移到新 master)。

哨兵的主要任務與實現目標

哨兵執行任務與目標

哨兵集羣工作原理

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

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

sentinel monitor <master-name> <ip> <redis-port> <quorum>

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

帶着這些問題,跟着「碼哥字節」一起追本溯源,深入哨兵集羣心臟。

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

65 哥:哨兵之間是如何知道彼此的?

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

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

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

Redis pub/sub 機制

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

Redis 通過頻道的方式對消息進行分別管理,這裏的頻道其實就是不同的微信羣。比如“碼哥字節讀者技術羣”就是專門分享技術的羣。朋友們可以關注公衆號,後臺回覆“加羣”,一起成長。

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

的確,哨兵之間建立連接形成集羣還不夠,還需要跟 slave 建立連接,不然沒法監控他們,無法對主從庫進行心跳判斷。

除此之外,如果發生了主從切換也得通知 slave 重新跟新 master 建立連接執行數據同步。關於主從架構數據同步原理可移步《Redis 高可用篇:你管這叫主從架構數據一致性同步》。

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

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

如圖所示,哨兵 2 向 Master 發送 INFO 命令,Master 就把 slave 列表返回給哨兵 2,哨兵 2 便根據 slave 列表連接信息與每一個 slave 建立連接,並基於此連接實現持續監控。

剩下的哨兵也同理基於此實現監控。

INFO命令獲取slave信息

選擇哨兵執行主從切換

65 哥:master 嗝屁了以後,哨兵這麼多,那到底讓哪一個哨兵來執行新 master 切換呢?

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

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

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

sentinel monitor <master-name> <ip> <redis-port> <quorum>

比如一共 3 個哨兵組成集羣,那麼 quorum 就可以配置成 2,當一個哨兵獲得了 2 張贊成票,就可以標記 master “客觀下線”,當然這個票包含自己的那一票。

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

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

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

如果哨兵集羣有 2 個實例,此時,一個哨兵要想成爲 Leader,必須獲得 2 票,而不是 1 票。所以,如果有個哨兵掛掉了,那麼,此時的集羣是無法進行主從庫切換的。因此,通常我們至少會配置 3 個哨兵實例。

這也是爲啥哨兵集羣部署成單數的原因,雙數的話多餘浪費。

選舉流程如下圖所示:

Redis哨兵執行主從切換

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

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

當然是召開新聞發佈會呀,邀請消息相關類型的媒體報道傳播,感興趣的人自然就去關注訂閱相關事件,並根據事件做出行動。

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

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

master 下線事件

  • +sdown:進入“主觀下線”狀態;
  • -sdown:退出“主觀下線”狀態;
  • +odown:進入“客觀下線”狀態;
  • -odown:退出“客觀下線”狀態;

slave 重新配置事件

  • +slave-reconf-sent:哨兵發送 replicaof 命令重新配置從庫;
  • +slave-reconf-inprog:slave 配置了新 master,但是尚未進行同步;
  • +slave-reconf-done:slave 配置了新 master,並與新 master 完成了數據同步;

新主庫切換

+switch-master:master 地址發生了變化。

知道了這些頻道之後,就可以讓客戶端從哨兵這裏訂閱消息了。客戶端讀取哨兵的配置文件後,可以獲得哨兵的地址和端口,和哨兵建立網絡連接。

然後,我們可以在客戶端執行訂閱命令,來獲取不同的事件消息。

舉個栗子:如下指令訂閱“所有實例進入客觀下線狀態的事件”

SUBSCRIBE +odown

注意事項與配置說明

發現了沒,Redis 的 pub/sub 發佈訂閱機制尤其重要,有了 pub/sub 機制,哨兵和哨兵之間、哨兵和從庫之間、哨兵和客戶端之間就都能建立起連接了,各種事件的發佈也是通過這個機制實現。

down-after-milliseconds

Sentinel 配置文件中的 down-after-milliseconds 選項指定了 Sentinel 判斷實例進入主觀下線所需的時間長度:如果一個實例在 down-after-milliseconds 毫秒內,連續向 Sentinel 返回無效回覆,那麼 Sentinel 會修改這個實例所對應數據,以此來表示這個實例已經進入主觀下線狀態。

要保證所有哨兵實例的配置是一致的,尤其是主觀下線的判斷值 down-after-milliseconds。因爲這個值在不同的哨兵實例上配置不一致,導致哨兵集羣一直沒有對有故障的主庫形成共識,也就沒有及時切換主庫,最終的結果就是集羣服務不穩定

down-after-milliseconds * 10

down-after-milliseconds 是我們認定主從庫斷連的最大連接超時時間。如果在 down-after-milliseconds 毫秒內,主從節點都沒有通過網絡聯繫上,我們就可以認爲主從節點斷連了。如果發生斷連的次數超過了 10 次,就說明這個從庫的網絡狀況不好,不適合作爲新主庫。

總結

哨兵主要任務

Redis 哨兵機制是實現 Redis 不間斷服務的高可用手段之一。主從架構集羣的數據同步,是數據可靠的基礎保障;主庫宕機,自動執行主從切換是服務不間斷的關鍵支撐。

Redis 哨兵機制實現了主從庫的自動切換,再也不怕跟女盆友麼麼噠的時候 master 宕機了:

  • 監控 master 與 slave 運行狀態,判斷是否客觀下線;
  • master 客觀下線後,選擇一個 slave 切換成 master;
  • 通知 slave 和客戶端新 master 信息。

哨兵集羣原理

爲了避免單個哨兵故障後無法進行主從切換,以及爲了減少誤判率,又引入了哨兵集羣;哨兵集羣又需要有一些機制來支撐它的正常運行:

  • 基於 pub/sub 機制實現哨兵集羣之間的通信;
  • 基於 INFO 命令獲取 slave 列表,幫助 哨兵與 slave 建立連接;
  • 通過哨兵的 pub/sub,實現了與客戶端和哨兵之間的事件通知。

主從切換,並不是隨意選擇一個哨兵就可以執行,而是通過投票仲裁,選擇一個 Leader,由這個 Leader 負責主從切換。

一起交流

下一篇「碼哥字節」將帶來 《Redis 高可用篇:Cluster 集羣,是兄弟就跟我一起扛》,關注我,獲取真正的硬核知識點。

另外技術讀者羣也開通了,後臺回覆「加羣」獲取「碼哥字節」作者微信交流或者提出建議,一起成長交流。羣裏有 N 多大廠的大佬,也可內推哦。

以上就是 Redis 哨兵集羣原理詳解,覺得不錯請點贊、分享,「碼哥字節」感激不盡。

參考資料

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