06 | 哨兵机制: 主库挂了, 如何不间断服务
哨兵模式主從數據同步
- 1. 前言
- 2.哨兵機制的基本流程
- 3.如何選定新主庫
1. 前言
??無論是寫服務中斷,還是從庫無法進行數據同步,都是不能接受的。所以,如果主庫掛了,我們就需要運行一個新主庫,比如說把一個從庫切換為主庫,把它當成主庫。這就涉及到三個問題:
- 主庫真的掛了嗎?
- 該選擇哪個從庫作為主庫?
- 怎么把新主庫的相關信息通知給從庫和客戶端呢?
??這就要提到哨兵機制了。在 Redis 主從集群中,哨兵機制是實現主從庫自動切換的關鍵機制,它有效地解決了主從復制模式下故障轉移的這三個問題。
2.哨兵機制的基本流程
??哨兵其實就是一個運行在特殊模式下的 Redis 進程,主從庫實例運行的同時,它也在運行。哨兵主要負責的就是三個任務:監控、選主(選擇主庫)和通知。
- 我們先看監控。監控是指哨兵進程在運行時,周期性地給所有的主從庫發送 PING 命令,檢測它們是否仍然在線運行。如果從庫沒有在規定時間內響應哨兵的 PING 命令,哨兵就會把它標記為“下線狀態”;同樣,如果主庫也沒有在規定時間內響應哨兵的 PING 命令,哨兵就會判定主庫下線,然后開始自動切換主庫的流程。
- 這個流程首先是執行哨兵的第二個任務,選主。主庫掛了以后,哨兵就需要從很多個從庫里,按照一定的規則選擇一個從庫實例,把它作為新的主庫。這一步完成后,現在的集群里就有了新主庫。
- 然后,哨兵會執行最后一個任務:通知。在執行通知任務時,哨兵會把新主庫的連接信息發給其他從庫,讓它們執行 replicaof 命令,和新主庫建立連接,并進行數據復制。同時,哨兵會把新主庫的連接信息通知給客戶端,讓它們把請求操作發到新主庫上。
??在這三個任務中,通知任務相對來說比較簡單,哨兵只需要把新主庫信息發給從庫和客戶端,讓它們和新主庫建立連接就行,并不涉及決策的邏輯。但是,在監控和選主這兩個任務中,哨兵需要做出兩個決策: - 在監控任務中,哨兵需要判斷主庫是否處于下線狀態;
- 在選主任務中,哨兵也要決定選擇哪個從庫實例作為主庫。
主觀下線和客觀下線
??哨兵進程會使用 PING 命令檢測它自己和主、從庫的網絡接情況,用來判斷實例的狀態。如果哨兵發現主庫或從庫對 PING 命令的響應超時了,那么,哨兵就會先把它標記為“主觀下線”
??如果檢測的是從庫,那么,哨兵簡單地把它標記為“主觀下線”就行了,因為從庫的下線影響一般不太大,集群的對外服務不會間斷。
??但是,如果檢測的是主庫,那么,哨兵還不能簡單地把它標記為“主觀下線”,開啟主從切換。因為很有可能存在這么一個情況:那就是哨兵誤判了,其實主庫并沒有故障。一旦哨兵判斷主庫下線了,就會開始選擇新主庫,并讓從庫和新主庫進行數據同步,這個過程本身就會有開銷,例如,哨兵要花時間選出新主庫,從庫也需要花時間和新主庫同步。而在誤判的情況下,主庫本身根本就不需要進行切換的,所以這個過程的開銷是沒有價值的。正因為這樣,我們需要判斷是否有誤判,以及減少誤判。
??哨兵機制也是類似的,它通常會采用多實例組成的集群模式進行部署,這也被稱為哨兵集群。引入多個哨兵實例一起來判斷,就可以避免單個哨兵因為自身網絡狀況不好,而誤判。
??在判斷主庫是否下線時,不能由一個哨兵說了算,只有大多數的哨兵實例,都判斷主庫已經“主觀下線”了,主庫才會被標記為“客觀下線”,這個叫法也是表明主庫下線成為一個客觀事實了。這個判斷原則就是:少數服從多數。同時,這會進一步觸發哨兵開始主從切換流程。
如下圖所示,
??Redis 主從集群有一個主庫、三個從庫,還有三個哨兵實例。在圖片的左邊,哨兵 2 判斷主庫為“主觀下線”,但哨兵 1 和 3 卻判定主庫是上線狀態,此時,主庫仍然被判斷為處于上線狀態。在圖片的右邊,哨兵 1 和 2 都判斷主庫為“主觀下線”,此時,即使哨兵 3 仍然判斷主庫為上線狀態,主庫也被標記為“客觀下線”了。
??簡單來說,“客觀下線”的標準就是,當有 N 個哨兵實例時,最好要有 N/2 + 1 個實例判斷主庫為“主觀下線”,才能最終判定主庫為“客觀下線”。這樣一來,就可以減少誤判的概率,也能避免誤判帶來的無謂的主從庫切換。(當然,有多少個實例做出“主觀下線”的判斷才可以,可以由 Redis 管理員自行設定)。
3.如何選定新主庫
??一般來說,我把哨兵選擇新主庫的過程稱為“篩選 + 打分”。簡單來說,我們在多個從庫中,先按照一定的篩選條件,把不符合條件的從庫去掉。然后,我們再按照一定的規則,給剩下的從庫逐個打分,將得分最高的從庫選為新主庫,如下圖所示:
??在選主時,除了要檢查從庫的當前在線狀態,還要判斷它之前的網絡連接狀態。如果從庫總是和主庫斷連,而且斷連次數超出了一定的閾值,我們就有理由相信,這個從庫的網絡狀況并不是太好,就可以把這個從庫篩掉了。具體怎么判斷呢?你使用配置項 down-after-milliseconds * 10。其中,down-after-milliseconds 是我們認定主從庫斷連的最大連接超時時間。如果在 down-after-milliseconds 毫秒內,主從節點都沒有通過網絡聯系上,我們就可以認為主從節點斷連了。如果發生斷連的次數超過了 10 次,就說明這個從庫的網絡狀況不好,不適合作為新主庫。
??好了,這樣我們就過濾掉了不適合做主庫的從庫,完成了篩選工作。
??接下來就要給剩余的從庫打分了。我們可以分別按照三個規則依次進行三輪打分,這三個規則分別是從庫優先級、從庫復制進度以及從庫 ID 號。只要在某一輪中,有從庫得分最高,那它就是主庫了,選主過程到此結束。如果沒有出現得分最高的從庫,那么就繼續進行下一輪。
-
第一輪:優先級最高的從庫得分高
??用戶可以通過 slave-priority 配置項,給不同的從庫設置不同優先級。比如,你有兩個從庫,它們的內存大小不一樣,你可以手動給內存大的實例設置一個高優先級。在選主時,哨兵會給優先級高的從庫打高分,如果有一個從庫優先級最高,那么它就是新主庫了。如果從庫的優先級都一樣,那么哨兵開始第二輪打分。 -
第二輪:和舊主庫同步程度最接近的從庫得分高
??這個規則的依據是,如果選擇和舊主庫同步最接近的那個從庫作為主庫,那么,這個新主庫上就有最新的數據。
??如何判斷從庫和舊主庫間的同步進度呢?
??主從庫同步時有個命令傳播的過程。在這個過程中,主庫會用master_repl_offset 記錄當前的最新寫操作在 repl_backlog_buffer 中的位置,而從庫會用 slave_repl_offset 這個值記錄當前的復制進度。
??此時,我們想要找的從庫,它slave_repl_offset 需要最接近 master_repl_offset。如果在所有從庫中,有從庫的 slave_repl_offset 最接近 master_repl_offset,那么它的得分就最高,可以作為新主庫。
??就像下圖所示,舊主庫的 master_repl_offset 是 1000,從庫 1、2 和 3 的slave_repl_offset 分別是 950、990 和 900,那么,從庫 2 就應該被選為新主庫。
??當然,如果有兩個從庫的 slave_repl_offset 值大小是一樣的(例如,從庫 1 和從庫 2 的slave_repl_offset 值都是 990),我們就需要給它們進行第三輪打分了。 -
第三輪:ID 號小的從庫得分高。
??每個實例都會有一個 ID,這個 ID 就類似于這里的從庫的編號。目前,Redis 在選主庫時,有一個默認的規定:在優先級和復制進度都相同的情況下,ID 號最小的從庫得分最高,會被選為新主庫。到這里,新主庫就被選出來了,“選主”
??這個過程就完成了。我們再回顧下這個流程。首先,哨兵會按照在線狀態、網絡狀態,篩選過濾掉一部分不符合要求的從庫,然后,依次按照優先級、復制進度、ID 號大小再對剩余的從庫進行打分,只要有得分最高的從庫出現,就把它選為新主庫。
總結
以上是生活随笔為你收集整理的06 | 哨兵机制: 主库挂了, 如何不间断服务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 05丨数据同步:主从库如何实现数据一致
- 下一篇: 07丨切片集群:数据增多了,是该加内存还