Redis 的哨兵機制自動完成了以下三大功能,從而實現了主從庫的自動切換,可以降低 Redis 叢集的運維開銷:
- 監控主庫執行狀態,並判斷主庫是否客觀下線;
- 在主庫客觀下線後,選取新主庫;
- 選出新主庫後,通知從庫和客戶端。
一、為什麼需要哨兵
主從模式下,如果主庫發生故障了,那就直接會影響到從庫的同步,因為從庫沒有相應的主庫可以進行資料複製操作了。
而且,如果客戶端傳送的都是讀操作請求,那還可以由從庫繼續提供服務,這在純讀的業務場景下還能被接受。但是,一旦有寫操作請求了,按照主從庫模式下的讀寫分離要求,需要由主庫來完成寫操作。
此時,也沒有例項可以來服務客戶端的寫操作請求了,如下圖所示:
無論是寫服務中斷,還是從庫無法進行資料同步,都是不能接受的。所以,如果主庫掛了,我們就需要執行一個新主庫,比如說把一個從庫切換為主庫,把它當成主庫。
這就涉及到三個問題:
- 主庫真的掛了嗎?
- 該選擇哪個從庫作為主庫?
- 怎麼把新主庫的相關資訊通知給從庫和客戶端呢?
二、哨兵機制的基本流程
哨兵其實就是一個執行在特殊模式下的 Redis 程式,主從庫例項執行的同時,它也在執行。
哨兵主要負責的就是三個任務:監控、選主(選擇主庫)和通知。
1、監控
監控是指哨兵程式在執行時,週期性地給所有的主從庫傳送 PING 命令,檢測它們是否仍然線上執行。
如果從庫沒有在規定時間內響應哨兵的 PING 命令,哨兵就會把它標記為“下線狀態”;同樣,如果主庫也沒有在規定時間內響應哨兵的 PING 命令,哨兵就會判定主庫下線,然後開始自動切換主庫的流程。
2、選主
這個流程首先是執行哨兵的第二個任務,選主。
主庫掛了以後,哨兵就需要從很多個從庫裡,按照一定的規則選擇一個從庫例項,把它作為新的主庫。這一步完成後,現在的叢集裡就有了新主庫。
3、通知
然後,哨兵會執行最後一個任務:通知。
在執行通知任務時,哨兵會把新主庫的連線資訊發給其他從庫,讓它們執行 replicaof 命令,和新主庫建立連線,並進行資料複製。同時,哨兵會把新主庫的連線資訊通知給客戶端,讓它們把請求操作發到新主庫上。
在這三個任務中,通知任務相對來說比較簡單,哨兵只需要把新主庫資訊發給從庫和客戶端,讓它們和新主庫建立連線就行,並不涉及決策的邏輯。但是,在監控和選主這兩個任務中,哨兵需要做出兩個決策:
- 在監控任務中,哨兵需要判斷主庫是否處於下線狀態;
- 在選主任務中,哨兵也要決定選擇哪個從庫例項作為主庫。
三、主庫下線和選主判斷
1、哨兵叢集
為了降低誤判率,在實際應用時,哨兵機制通常採用多例項的方式進行部署,多個哨兵例項透過“少數服從多數”的原則,來判斷主庫是否客觀下線。一般來說,我們可以部署三個哨兵,如果有兩個哨兵認定主庫“主觀下線”,就可以開始切換過程。當然,如果你希望進一步提升判斷準確率,也可以再適當增加哨兵個數,比如說使用五個哨兵。
2、如何判斷
哨兵程式會使用 PING 命令檢測它自己和主、從庫的網路連線情況,用來判斷例項的狀態。
如果哨兵發現主庫或從庫對 PING 命令的響應超時了,那麼,哨兵就會先把它標記為“主觀下線”。
如果檢測的是從庫,那麼,哨兵簡單地把它標記為“主觀下線”就行了,因為從庫的下線影響一般不太大,叢集的對外服務不會間斷。
但是,如果檢測的是主庫,那麼,哨兵還不能簡單地把它標記為“主觀下線”,開啟主從切換。因為很有可能存在這麼一個情況:那就是哨兵誤判了,其實主庫並沒有故障。可是,一旦啟動了主從切換,後續的選主和通知操作都會帶來額外的計算和通訊開銷。
3、如何選定新主庫?
一般來說,我把哨兵選擇新主庫的過程稱為“篩選 + 打分”。簡單來說,我們在多個從庫中,按照一定的篩選條件,把不符合條件的從庫去掉。