Redis哨兵實現原理
本文內容出自李子驊的《Redis入門指南》
一、讀取配置檔案內容
一個哨兵程序啟動時會讀取配置檔案的內容,通過如下的配置找出需要監控的主資料庫:
sentinel monitor master-name ip redis-port quorum
- master-name是一個由大小寫字母、數字和'.','-','_'組成的主資料庫的名字。
因為考慮到故障恢復後當前監控的系統的主資料庫的地址和埠會產生變化,所以哨兵提供了命令可以通過主資料庫的名字獲取當前系統的主資料庫的地址和埠號。 - ip表示當前系統中主資料庫的地址,而redis-port則表示埠號。
- quorum用來表示執行故障恢復操作前至少需要幾個哨兵節點同意,作用可檢視下文。
一個哨兵節點可以同時監控多個Redis主從系統,只需要提供多個sentinel monitor配置即可,例如
sentinel moni tor mymaster 127.0.0.1 6379 2
sentinel monitor othermaater 192.168.1.3 6380 4
同時多個哨兵節點也可以同時監控同一個 Redis主從系統,從而形成網狀結構。
配置檔案中還可以定義其他監控相關的引數,每個配置選項都包含主資料庫的名字使得監控不同主資料庫時可以使用不同的配置引數。例如:
sentinel down-after-milliseconds mymaster 60000 sentinel down-after-milliseconds othermaster 10000
上面的兩行配置分別配置了mymaster和othermaster的down-after-milliseconds選項分別為60000和10000。作用可檢視下文
二、建立連線
哨兵啟動後,會與要監控的主資料庫建立兩條連線,這兩個連線的建立方式與普通的Redis客戶端無異。
-
其中一條連線用來訂閱該主資料的
sentinel:he11o
頻道以獲取其他同樣監控該資料庫的哨兵節點的資訊 -
使用另外一條連線來定期向主資料庫傳送INFo等命令來獲取主資料庫本身的資訊。
之所以哨兵會使用另一條連線傳送這些命令,是因為當客戶端的連線進入訂閱模式時就不能再執行其他命令了
和主資料庫的連線建立完成後,哨兵會定時執行下面3個操作。
- 每10秒哨兵會向主資料庫和從資料庫傳送INFO命令。
- 每2秒哨兵會向主資料庫和從資料庫的
sentinel:he11o
頻道傳送自己的資訊。 - 每1秒哨兵會向主資料庫、從資料庫和其他哨兵節點發送PING命令
這3個操作貫穿哨兵程序的整個生命週期中,非常重要,可以說了解了這3個操作的意義就能夠了解哨兵工作原理的一半內容了。
三、哨兵的三個定期操作
-
傳送INFO命令使得哨兵可以獲得當前資料庫的相關資訊(包括執行ID、複製資訊等)從而實現新節點的自動發現。
前面說配置哨兵監控Redis主從系統時只需要指定主資料庫的資訊即可
因為哨兵正是藉助NFo命令來獲取所有複製該主資料庫的從資料庫資訊的。啟動後,哨兵向主資料庫傳送INFO命令,通過解析返回結果來得知從資料庫列表,而後對每個從資料庫同樣建立兩個連線,兩個連線的作用和前文介紹的與主資料庫建立的兩個連線完全一致。在此之後,哨兵會每10秒定時向已知的所有主從資料庫傳送
INFO
命令來獲取資訊更新並進行相應操作,比如- 對新增的從資料庫建立連線並加入監控列表
- 對主從資料庫的角色變化(由故障恢復操作引起)進行資訊更新等
-
接下來哨兵向主從資料庫的
sentinel:he11o
頻道傳送資訊來與同樣監控該資料庫的哨兵分享自己的資訊。- 傳送的訊息內容為:
<哨兵的地址>,<哨兵的埠>,<哨兵的執行ID>,<哨肖兵的配置版本>,<主資料庫的名字>,
<主資料庫的地址>,<主資料庫的埠>,<主資料庫的配置版本>
可以看到訊息包括的哨兵的基本資訊,以及其監控的主資料庫的資訊
- 哨兵會訂閱每個其監控的資料庫的
sentinel:he11o
頻道,所以當其他哨兵收到訊息後,會判斷髮訊息的哨兵是不是新發現的哨兵。如果是則將其加入已發現的哨兵列表中並建立一個到其的連線(與資料庫不同,哨兵與哨兵之間只會建立一條連線用來發送命令,而不需要建立另外一條連線來訂閱頻道,因為哨兵只需要訂閱資料庫的頻道即可實現自動發現其他哨兵)。同時哨兵會判斷資訊中主資料庫的配置版本,如果該版本比當前記錄的主資料庫的版本高,則更新主資料庫的資料。
- 傳送的訊息內容為:
-
實現了自動發現從資料庫和其他哨兵節點後,哨兵要做的就是定時監控和節點有沒有停止服務。這是通過每隔一定時間向這些節點發送PING命令實現的。
時間間隔與down-after-milliseconds選項有關- 當down-after-milliseconds的值小於1秒時,哨兵會每隔down-after-milliseconds指定的時間傳送一次PING命令,
- 當down-after-milliseconds的值大於1秒時,哨兵會每隔1秒傳送一次PING命令
當超過down-after-milliseconds選項指定時間後,如果被PING的資料庫或節點仍然未進行回覆,則哨兵認為其主觀下線(subjectively down)。主觀下線表示從當前的哨兵程序看來,該節點已經下線。
如果該節點是主資料庫,則哨兵會進一步判斷是否需要對其進行故障恢復:
哨兵傳送
SENTINEL is-master-down-by-addr
命令詢問其他哨兵節點以瞭解他們是否也認為該主資料庫主觀下線,如果達到指定數量時,哨兵會認為其客觀下線(objectively down),並選舉領頭的哨兵節點對主從系統發起故障恢復。
這個指定數量即為前文介紹的quorum
引數,只有當至少quorum個Sentinel節點(包括當前節點)認為該主資料庫主觀下線時,當前哨兵節點才會認為該主資料庫客觀下線。
四、選舉領頭哨兵步驟
雖然當前哨兵節點發現了主資料庫客觀下線,需要故障恢復,但是故障恢復需要由領頭的哨兵來完成,這樣可以保證同一時間只有一個哨兵節點來執行故障恢復。
選舉領頭哨兵的過程使用了Raft演算法,具體過程如下。
- 發現主資料庫客觀下線的哨兵節點(下面稱作A)向每個哨兵節點發送命令,要求對方選自己成為領頭哨兵.
- 如果目標哨兵節點沒有選過其他人,則會同意將A設定成領頭哨兵.
- 如果A發現有超過半數且超過
quorum
引數值的哨兵節點同意選自己成為領頭哨兵,則A成功稱為領頭哨兵。 - 當有多個哨兵節點同時參選領頭哨兵,則會出現沒有任何節點當選的可能。此時每個參選節點將等待一個隨機時間重新發起參選請求,進行下一輪選舉,直到選舉成功。
具體過程可以參考Raft演算法的過程http://raftconsensus.github.io/。因為要成為領頭哨兵必須有超過半數的哨兵節點支援,所以每次選舉最多隻會選出一個領頭哨兵。
選出領頭哨兵後,領頭哨兵將會開始對主資料庫進行故障恢復。
五、故障恢復
- 首先領頭哨兵將從停止服務的主資料庫的從資料庫中挑選一個來充當新的主資料庫。
挑選的依據如下。- 所有線上的從資料庫中,選擇優先順序最高的從資料庫。優先順序可以通過
slave-priority
選項來設定。 - 如果有多個最高優先順序的從資料庫,則複製的命令偏移量越大(即複製越完整)越優先。
命令偏移量可參考redis的增量複製
- 如果以上條件都一樣,則選擇
執行ID
較小的從資料庫。
- 所有線上的從資料庫中,選擇優先順序最高的從資料庫。優先順序可以通過
- 選出一個從資料庫後,領頭哨兵將向從資料庫傳送
SLAVEOF NO ONE
命令使其升格為主資料庫。領頭哨兵向其他從資料庫傳送SLAVEOF
命令來使其成為新主資料庫的從資料庫。 - 最後一步則是更新內部的記錄,將已經停止服務的舊的主資料庫更新為新的主資料庫的從資料庫,使得當其恢復服務時自動以從資料庫的身份繼續服務。