08 | 哨兵叢集:哨兵掛了,主從庫還能切換嗎?
阿新 • • 發佈:2022-04-07
上節課,我們學習了哨兵機制,它可以實現主從庫的自動切換。通過部署多個例項,就形
成了一個哨兵叢集。哨兵叢集中的多個例項共同判斷,可以降低對主庫下線的誤判率。
但是,我們還是要考慮一個問題:如果有哨兵例項在執行時發生了故障,主從庫還能正常
切換嗎?
實際上,一旦多個例項組成了哨兵叢集,即使有哨兵例項出現故障掛掉了,其他哨兵還能
繼續協作完成主從庫切換的工作,包括判定主庫是不是處於下線狀態,選擇新主庫,以及
通知從庫和客戶端。
如果你部署過哨兵叢集的話就會知道,在配置哨兵的資訊時,我們只需要用到下面的這個
配置項,設定主庫的 IP 和埠,並沒有配置其他哨兵的連線資訊。
這些哨兵例項既然都不知道彼此的地址,又是怎麼組成叢集的呢?要弄明白這個問題,我
們就需要學習一下哨兵叢集的組成和執行機制了。
理。所謂的頻道,實際上就是訊息的類別。當訊息類別相同時,它們就屬於同一個頻道。
反之,就屬於不同的頻道。只有訂閱了同一個頻道的應用,才能通過釋出的訊息進行資訊
交換。
在主從叢集中,主庫上有一個名為“
__sentinel__:hello”的頻道,不同哨兵就是通過
它來相互發現,實現互相通訊的。
我來舉個例子,具體說明一下。在下圖中,哨兵 1 把自己的 IP(172.16.19.3)和埠
(26579)釋出到“
__sentinel__:hello”頻道上,哨兵 2 和 3 訂閱了該頻道。那麼
此時,哨兵 2 和 3 就可以從這個頻道直接獲取哨兵 1 的 IP 地址和埠號。
然後,哨兵 2、3 可以和哨兵 1 建立網路連線。通過這個方式,哨兵 2 和 3 也可以建立網
絡連線,這樣一來,哨兵叢集就形成了。它們相互間可以通過網路連線進行通訊,比如說
對主庫有沒有下線這件事兒進行判斷和協商。
sentinel monitor <master-name> <ip> <redis-port> <quorum>
基於 pub/sub 機制的哨兵叢集組成
哨兵例項之間可以相互發現,要歸功於 Redis 提供的 pub/sub 機制,也就是釋出 / 訂閱 機制。 哨兵只要和主庫建立起了連線,就可以在主庫上釋出訊息了,比如說釋出它自己的連線信 息(IP 和埠)。同時,它也可以從主庫上訂閱訊息,獲得其他哨兵釋出的連線資訊。當 多個哨兵例項都在主庫上做了釋出和訂閱操作後,它們之間就能知道彼此的 IP 地址和端 口。 除了哨兵例項,我們自己編寫的應用程式也可以通過 Redis 進行訊息的釋出和訂閱。所 以,為了區分不同應用的訊息,Redis 會以頻道的形式,對這些訊息進行分門別類的管
哨兵除了彼此之間建立起連線形成叢集外,還需要和從庫建立連線。這是因為,在哨兵的 監控任務中,它需要對主從庫都進行心跳判斷,而且在主從庫切換完成後,它還需要通知 從庫,讓它們和新主庫進行同步。 那麼,哨兵是如何知道從庫的 IP 地址和埠的呢? 這是由哨兵向主庫傳送 INFO 命令來完成的。就像下圖所示,哨兵 2 給主庫傳送 INFO 命 令,主庫接受到這個命令後,就會把從庫列表返回給哨兵。接著,哨兵就可以根據從庫列 表中的連線資訊,和每個從庫建立連線,並在這個連線上持續地對從庫進行監控。哨兵 1 和 3 可以通過相同的方法和從庫建立連線。
你看,通過 pub/sub 機制,哨兵之間可以組成叢集,同時,哨兵又通過 INFO 命令,獲得 了從庫連線資訊,也能和從庫建立連線,並進行監控了。 但是,哨兵不能只和主、從庫連線。因為,主從庫切換後,客戶端也需要知道新主庫的連 接資訊,才能向新主庫傳送請求操作。所以,哨兵還需要完成把新主庫的資訊告訴客戶端 這個任務。 而且,在實際使用哨兵時,我們有時會遇到這樣的問題:如何在客戶端通過監控瞭解哨兵 進行主從切換的過程呢?比如說,主從切換進行到哪一步了?這其實就是要求,客戶端能 夠獲取到哨兵叢集在監控、選主、切換這個過程中發生的各種事件。 此時,我們仍然可以依賴 pub/sub 機制,來幫助我們完成哨兵和客戶端間的資訊同步。
基於 pub/sub 機制的客戶端事件通知
從本質上說,哨兵就是一個執行在特定模式下的 Redis 例項,只不過它並不服務請求操 作,只是完成監控、選主和通知的任務。所以,每個哨兵例項也提供 pub/sub 機制,客戶 端可以從哨兵訂閱訊息。哨兵提供的訊息訂閱頻道有很多,不同頻道包含了主從庫切換過 程中的不同關鍵事件。 頻道有這麼多,一下子全部學習容易丟失重點。為了減輕你的學習壓力,我把重要的頻道 彙總在了一起,涉及幾個關鍵事件,包括主庫下線判斷、新主庫選定、從庫重新配置。知道了這些頻道之後,你就可以讓客戶端從哨兵這裡訂閱訊息了。具體的操作步驟是,客 戶端讀取哨兵的配置檔案後,可以獲得哨兵的地址和埠,和哨兵建立網路連線。然後, 我們可以在客戶端執行訂閱命令,來獲取不同的事件訊息。 舉個例子,你可以執行如下命令,來訂閱“所有例項進入客觀下線狀態的事件”:
SUBSCRIBE +odown當然,你也可以執行如下命令,訂閱所有的事件:
PSUBSCRIBE *當哨兵把新主庫選擇出來後,客戶端就會看到下面的 switch-master 事件。這個事件表示 主庫已經切換了,新主庫的 IP 地址和埠資訊已經有了。這個時候,客戶端就可以用這裡 面的新主庫地址和埠進行通訊了。
switch-master <master name> <oldip> <oldport> <newip> <newport>
有了這些事件通知,客戶端不僅可以在主從切換後得到新主庫的連線資訊,還可以監控到
主從庫切換過程中發生的各個重要事件。這樣,客戶端就可以知道主從切換進行到哪一步
了,有助於瞭解切換進度。
好了,有了 pub/sub 機制,哨兵和哨兵之間、哨兵和從庫之間、哨兵和客戶端之間就都能
建立起連線了,再加上我們上節課介紹主庫下線判斷和選主依據,哨兵叢集的監控、選主
和通知三個任務就基本可以正常工作了。不過,我們還需要考慮一個問題:主庫故障以
後,哨兵叢集有多個例項,那怎麼確定由哪個哨兵來進行實際的主從切換呢?
由哪個哨兵執行主從切換?
確定由哪個哨兵執行主從切換的過程,和主庫“客觀下線”的判斷過程類似,也是一 個“投票仲裁”的過程。在具體瞭解這個過程前,我們再來看下,判斷“客觀下線”的仲 裁過程。 哨兵叢集要判定主庫“客觀下線”,需要有一定數量的例項都認為該主庫已經“主觀下 線”了。我在上節課向你介紹了判斷“客觀下線”的原則,接下來,我介紹下具體的判斷 過程。 任何一個例項只要自身判斷主庫“主觀下線”後,就會給其他例項傳送 is-master-down-by-addr 命令。接著,其他例項會根據自己和主庫的連線情況,做出 Y 或 N 的響應,Y 相 當於贊成票,N 相當於反對票。
一個哨兵獲得了仲裁所需的贊成票數後,就可以標記主庫為“客觀下線”。這個所需的贊 成票數是通過哨兵配置檔案中的 quorum 配置項設定的。例如,現在有 5 個哨兵, quorum 配置的是 3,那麼,一個哨兵需要 3 張贊成票,就可以標記主庫為“客觀下 線”了。這 3 張贊成票包括哨兵自己的一張贊成票和另外兩個哨兵的贊成票。 此時,這個哨兵就可以再給其他哨兵傳送命令,表明希望由自己來執行主從切換,並讓所 有其他哨兵進行投票。這個投票過程稱為“Leader 選舉”。因為最終執行主從切換的哨兵 稱為 Leader,投票過程就是確定 Leader。 在投票過程中,任何一個想成為 Leader 的哨兵,要滿足兩個條件:第一,拿到半數以上的 贊成票;第二,拿到的票數同時還需要大於等於哨兵配置檔案中的 quorum 值。以 3 個哨 兵為例,假設此時的 quorum 設定為 2,那麼,任何一個想成為 Leader 的哨兵只要拿到 2 張贊成票,就可以了。 這麼說你可能還不太好理解,我再畫一張圖片,展示一下 3 個哨兵、quorum 為 2 的選舉 過程
在 T1 時刻,S1 判斷主庫為“客觀下線”,它想成為 Leader,就先給自己投一張贊成票, 然後分別向 S2 和 S3 傳送命令,表示要成為 Leader。 在 T2 時刻,S3 判斷主庫為“客觀下線”,它也想成為 Leader,所以也先給自己投一張贊 成票,再分別向 S1 和 S2 傳送命令,表示要成為 Leader。 在 T3 時刻,S1 收到了 S3 的 Leader 投票請求。因為 S1 已經給自己投了一票 Y,所以它 不能再給其他哨兵投贊成票了,所以 S1 回覆 N 表示不同意。同時,S2 收到了 T2 時 S3 傳送的 Leader 投票請求。因為 S2 之前沒有投過票,它會給第一個向它傳送投票請求的哨 兵回覆 Y,給後續再發送投票請求的哨兵回覆 N,所以,在 T3 時,S2 回覆 S3,同意 S3 成為 Leader。 在 T4 時刻,S2 才收到 T1 時 S1 傳送的投票命令。因為 S2 已經在 T3 時同意了 S3 的投 票請求,此時,S2 給 S1 回覆 N,表示不同意 S1 成為 Leader。發生這種情況,是因為 S3 和 S2 之間的網路傳輸正常,而 S1 和 S2 之間的網路傳輸可能正好擁塞了,導致投票請 求傳輸慢了。 最後,在 T5 時刻,S1 得到的票數是來自它自己的一票 Y 和來自 S2 的一票 N。而 S3 除 了自己的贊成票 Y 以外,還收到了來自 S2 的一票 Y。此時,S3 不僅獲得了半數以上的 Leader 贊成票,也達到預設的 quorum 值(quorum 為 2),所以它最終成為了 Leader。接著,S3 會開始執行選主操作,而且在選定新主庫後,會給其他從庫和客戶端通 知新主庫的資訊。 如果 S3 沒有拿到 2 票 Y,那麼這輪投票就不會產生 Leader。哨兵叢集會等待一段時間 (也就是哨兵故障轉移超時時間的 2 倍),再重新選舉。這是因為,哨兵叢集能夠進行成 功投票,很大程度上依賴於選舉命令的正常網路傳播。如果網路壓力較大或有短時堵塞, 就可能導致沒有一個哨兵能拿到半數以上的贊成票。所以,等到網路擁塞好轉之後,再進 行投票選舉,成功的概率就會增加。 需要注意的是,如果哨兵叢集只有 2 個例項,此時,一個哨兵要想成為 Leader,必須獲得 2 票,而不是 1 票。所以,如果有個哨兵掛掉了,那麼,此時的叢集是無法進行主從庫切 換的。因此,通常我們至少會配置 3 個哨兵例項。這一點很重要,你在實際應用時可不能 忽略了。