1. 程式人生 > 其它 >《Redis設計與實現》讀書筆記(二十七) ——Redis哨兵(sentinel)主伺服器下線判斷與故障轉移

《Redis設計與實現》讀書筆記(二十七) ——Redis哨兵(sentinel)主伺服器下線判斷與故障轉移

《Redis設計與實現》讀書筆記(二十七) ——Redis哨兵(sentinel)主伺服器下線判斷與故障轉移

(原創內容,轉載請註明來源,謝謝)

一、主觀下線檢測

預設情況下,sentinel會每秒1次,向所有它建立的連線例項傳送ping命令,包括主從伺服器與其他的sentinel。通過例項返回判斷是否線上。

有效的回覆包括pong、loading和mastdown,無效的回覆包括超時的回覆以及前三個之外的回覆。

在sentinel的配置檔案中,down_after_milliseconds指定了sentinel判斷主觀下線的方式,主伺服器連續沒給出正確的回覆超過這個設定的時間,則表示該主伺服器被這個sentinel認定為主觀下線。

此時,sentinel會在自身記錄主伺服器的flags加上一個標籤,使得主伺服器此時的flags標籤變為SRI_MASTER|SRI_S_DOWN。

配置主觀下線的down_after_milliseconds,不僅sentinel會對該主伺服器進行這樣的判斷,也同樣會將該引數帶到該主伺服器下的全部從伺服器。

另外,不同的sentinel對同一個主伺服器,設定的主觀下線的值可以不同。每個sentinel會按照自身的配置檔案,來判斷檢測的主伺服器是否主觀下線。

二、客觀下線檢測

1、傳送檢測主觀下線命令

當sentinel認定該主伺服器主觀下線,會同時給其他幾個監測此主伺服器的sentinel傳送命令,確認在其他sentinel處是否也認為該主伺服器主觀下線。命令格式為:

         sentinel is-master-down-by-addr <ip><port> <current_epoch> <runid>

其中,runid如果是*,表示僅僅檢測該主伺服器是否主觀下線,如果是用sentinel的執行id,則表示選舉領頭sentinel。

2、接收命令回覆

sentinel會收到包含三個引數的multi bulk回覆,如下:

1)<down_state>

目標sentinel對該主伺服器的檢查結果,1表示該sentinel也認為主伺服器主觀下線,0表示未下線。

2)<leader_runid>

*或者sentinelid,*表示主伺服器,sentinelid表示區域性主伺服器id。

3)<leader_epoch>

領頭紀元,用於選舉主伺服器。

3、客觀下線

當回覆的sentinel中,認為該主伺服器主觀下線的個數超過配置檔案中設定的quorum的值(包括自身是sentinel),則sentinel認為該主伺服器客觀下線。

sentinel會給該主伺服器加上一個新的flags標籤,總體標籤變為:SRI_MASTER|SRI_S_DOWN|SRI_O_DOWN。

不同的sentinel可以設定不同的客觀下線quorum數量,因此可能部分sentinel認為主伺服器客觀下線,另一部分認為還沒客觀下線。

三、選舉領頭sentinel

當一個主伺服器被判定為客觀下線,監視該主伺服器的各個sentinel,會協商選舉一個領頭sentinel,對下線主伺服器進行故障轉移工作。

方式如下:

1)所有線上的sentinel都有參選資格。

2)每次選舉領頭sentinel,無論是否成功,所有sentinel的配置紀元(epoch)都會加一,這個epoch即計數器。

3)在每一輪的epoch,每個sentinel都有一次機會將某個sentinel設定為區域性領頭sentinel,設定後在本輪的epoch不可更改。

4)每個發現主伺服器客觀下線的sentinel都會要求其他的sentinel將自身設定為區域性領頭。

5)當一個sentinel向另一個sentinel傳送sentinelis-master-down-by-addr <ip> <port> <current_epoch> <runid>,其中的runid不是*,而是源sentinel的執行id,則表示源sentinel要求接收者將自身選舉為區域性領頭。

6)設定區域性領頭的規則是先到先得,先發送的會被設定為領頭,後面傳送的會被拒絕。

7)目標sentinel接收到第五步的命令後,回覆的結果中,<leader_runid>就是源sentinel的執行id,<leader_epoch>是本輪的epoch。

8)源sentinel接收到回覆後,會比對runid,如果和自身的一致,則表示目標sentinel已經將源sentinel設定為區域性領頭。

9)如果某個sentinel被設定為區域性領頭的數量,超過總sentinel的一半(不含正好一半的情況),則其稱為領頭sentinel。

10)因為需要半數以上支援,因此每次epoch只會有一個sentinel被選為領頭。

11)一定時間內,如果沒有選舉出領頭,則會在一段時間後,再次進行選舉。

四、故障轉移

選舉領頭後,領頭sentinel將進行故障轉移,工作包括:

1)在下線的主伺服器對應的從伺服器裡面,重新選一個主伺服器;

2)讓其餘的從伺服器都稱為新主伺服器的從伺服器;

3)把下線的舊主伺服器也設定為新主伺服器的從伺服器,這樣其上線後就以從伺服器的方式運作。

1、選出新主伺服器

sentinel會將下線的主伺服器的從伺服器列表中,選出一個從伺服器,選擇規則如下:

1)不考慮已經下線和斷線的從伺服器,以保證選出的是正常線上的。

2)不考慮最近5秒內沒有回覆過領頭sentinel的info命令的從伺服器,以保證選出的是成功通訊的。

3)不考慮所有和已下線主伺服器斷開連線超過down-after-millisecond*10毫秒的從伺服器,以保證選出的是資料最新的。

4)將剩餘的從伺服器,按照從伺服器優先順序選擇主伺服器。

5)如果優先順序一樣,則按照偏移量最大的選擇。

6)如果優先順序和偏移量都一樣的,按照執行ID最小的作為主伺服器。

選出主伺服器後,sentinel給其傳送slaveofno one命令,讓其變成主伺服器。並且,會每秒一次的頻率傳送info命令給新主伺服器(正常是10秒一次傳送info),直到回覆中role從slave變成master,表示升級成功。

2、修改其他從伺服器的複製目標

即給其餘的從伺服器,傳送slaveof<new_ip> <new_port>,讓其餘的從伺服器重新選則新的主伺服器。

3、將舊主伺服器變成從伺服器

由於其已經下線,無法直接傳送slaveof命令,sentinel會將其儲存在例項結構裡面,待其重新上線,再發送命令。

五、重點回顧

1、sentinel伺服器是執行在特殊模式下的redis伺服器,其命令表、預設埠都和redis伺服器有所不同,只接受7個客戶端的命令,預設埠是26379。

2、sentinel會讀入使用者的主從配置檔案,與每個要監視的主伺服器建立例項結構,並且建立命令連線和訂閱連線,命令連線用來發送ping、publish、info等命令,訂閱連線用來監聽該主伺服器下的所有從伺服器的狀態。sentinel同樣會和從伺服器建立這樣的兩個連線,但是和其他的sentinel只會建立命令連線,沒有訂閱連線。

3、sentinel通過向監聽的主伺服器傳送info命令,獲取並建立相關從伺服器的例項結構。info命令通常10秒1次,但是在重新選出的主伺服器還未完全從從伺服器轉成主伺服器時,是每秒傳送一次info。

4、對於所有監視主從伺服器的sentinel,伺服器會兩秒傳送一個__sentinel__:hello頻道內容,表示自己還線上。

5、每個sentinel也會從上述頻道接收到其他sentinel的資訊,並且更新到自身的相應的例項結構中。

6、sentinel每秒1次向所有例項結構(主、從伺服器以及其他sentinel伺服器)傳送ping命令,根據回覆判斷是否線上,超過規定時間仍是無效回覆,則認為該伺服器主觀下線。

7、當sentinel認為主伺服器主觀下線,會給其他sentinel傳送命令,查詢是否其他sentinel也認為其主觀下線。當收到的回覆中,認為主伺服器主觀下線的sentinel個數(含自身)超過設定的值,則sentinel認為該主伺服器客觀下線。

8、判斷主伺服器客觀下線後,sentinel會選出一個領頭sentinel,來進行故障轉移的工作,選舉主要是要拿到超過半數的臨時領頭。

9、故障轉移工作,包括從從伺服器中新選出一個主伺服器、將其他從伺服器複製的物件改為新主伺服器、將下線的舊主伺服器改為從伺服器。

——written by linhxx 2017.09.13