sentinal,中文名是哨兵node
哨兵是redis集羣架構中很是重要的一個組件,主要功能以下:redis
(1)集羣監控,負責監控redis master和slave進程是否正常工做。算法
(2)消息通知,若是某個redis實例有故障,那麼哨兵負責發送消息做爲報警通知給管理員。網絡
(3)故障轉移,若是master node掛掉了,會自動轉移到slave node上。架構
(4)配置中心,若是故障轉移發生了,通知client客戶端新的master地址。異步
哨兵自己也是分佈式的,做爲一個哨兵集羣去運行,互相協同工做:分佈式
(1)故障轉移時,判斷一個master node是宕機了,須要大部分的哨兵都贊成才行,涉及到了分佈式選舉的問題。ide
(2)即便部分哨兵節點掛掉了,哨兵集羣仍是能正常工做的,由於若是一個做爲高可用機制重要組成部分的故障轉移系統自己是單點的,那就很坑爹了。測試
目前採用的是sentinal 2版本,sentinal 2相對於sentinal 1來講,重寫了不少代碼,主要是讓故障轉移的機制和算法變得更加健壯和簡單spa
(1)哨兵至少須要3個實例,來保證本身的健壯性。
(2)哨兵 + redis主從的部署架構,是不會保證數據零丟失的,只能保證redis集羣的高可用性。
(3)對於哨兵 + redis主從這種複雜的部署架構,儘可能在測試環境和生產環境,都進行充足的測試和演練。
哨兵集羣必須部署2個以上節點,若是哨兵集羣僅僅部署了個2個哨兵實例,quorum=1
+----+ +----+
| M1 |---------| R1 |
| S1 | | S2 |
+----+ +----+
Configuration: quorum = 1
master宕機,s1和s2中只要有1個哨兵認爲master宕機就能夠進行切換,同時s1和s2中會選舉出一個哨兵來執行故障轉移,同時這個時候,須要majority,也就是大多數哨兵都是運行的,2個哨兵的majority就是2(2的majority=2,3的majority=2,5的majority=3,4的majority=2),2個哨兵都運行着,就能夠容許執行故障轉移。可是若是整個M1和S1運行的機器宕機了,那麼哨兵只有1個了,此時就沒有majority來容許執行故障轉移,雖然另一臺機器還有一個R1,可是故障轉移不會執行。
+----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+
Configuration: quorum = 2,majority
若是M1所在機器宕機了,那麼三個哨兵還剩下2個,S2和S3能夠一致認爲master宕機,而後選舉出一個來執行故障轉移,同時3個哨兵的majority是2,因此還剩下的2個哨兵運行着,就能夠容許執行故障轉移。
由於master -> slave的複製是異步的,因此可能有部分數據還沒複製到slave,master就宕機了,此時這些部分數據就丟失了。
腦裂,也就是說,某個master所在機器忽然脫離了正常的網絡,跟其餘slave機器不能鏈接,可是實際上master還運行着,此時哨兵可能就會認爲master宕機了,而後開啓選舉,將其餘slave切換成了master,這個時候,集羣裏就會有兩個master,也就是所謂的腦裂。
此時雖然某個slave被切換成了master,可是可能client還沒來得及切換到新的master,還繼續寫向舊master的數據可能也丟失了,所以舊master再次恢復的時候,會被做爲一個slave掛到新的master上去,本身的數據會清空,從新重新的master複製數據。
上面兩個配置能夠減小異步複製和腦裂致使的數據丟失:
min-slaves-to-write 1# 要求至少有1個slave,數據複製和同步的延遲不能超過10秒
min-slaves-max-lag 10#若是說一旦全部的slave,數據複製和同步的延遲都超過了10秒鐘,那麼這個時候,master就不會再接收任何請求了
有了min-slaves-max-lag這個配置,就能夠確保說,一旦slave複製數據和ack延時太長,就認爲可能master宕機後損失的數據太多了,那麼就拒絕寫請求,這樣能夠把master宕機時因爲部分數據未同步到slave致使的數據丟失下降的可控範圍內。
若是一個master出現了腦裂,跟其餘slave丟了鏈接,那麼上面兩個配置能夠確保說,若是不能繼續給指定數量的slave發送數據,並且slave超過10秒沒有給本身ack消息,那麼就直接拒絕客戶端的寫請求。這樣腦裂後的舊master就不會接受client的新數據,也就避免了數據丟失。上面的配置就確保了,若是跟任何一個slave丟了鏈接,在10秒後發現沒有slave給本身ack,那麼就拒絕新的寫請求。所以在腦裂場景下,最多就丟失10秒的數據。
sdown和odown兩種失敗狀態sdown是主觀宕機,就一個哨兵若是本身以爲一個master宕機了,那麼就是主觀宕機。odown是客觀宕機,若是quorum數量的哨兵都以爲一個master宕機了,那麼就是客觀宕機。
sdown達成的條件很簡單,若是一個哨兵ping一個master,超過了is-master-down-after-milliseconds指定的毫秒數以後,就主觀認爲master宕機。sdown到odown轉換的條件很簡單,若是一個哨兵在指定時間內,收到了quorum指定數量的其餘哨兵也認爲那個master是sdown了,那麼就認爲是odown了,客觀認爲master宕機。
哨兵互相之間的發現,是經過redis的pub/sub系統實現的,每一個哨兵都會往sentinel:hello這個channel裏發送一個消息,這時候全部其餘哨兵均可以消費到這個消息,並感知到其餘的哨兵的存在。每隔兩秒鐘,每一個哨兵都會往本身監控的某個master+slaves對應的sentinel:hello channel裏發送一個消息,內容是本身的host、ip和runid還有對這個master的監控配置。每一個哨兵也會去監聽本身監控的每一個master+slaves對應的sentinel:hello channel,而後去感知到一樣在監聽這個master+slaves的其餘哨兵的存在。每一個哨兵還會跟其餘哨兵交換對master的監控配置,互相進行監控配置的同步。
哨兵會負責自動糾正slave的一些配置,好比slave若是要成爲潛在的master候選人,哨兵會確保slave在複製現有master的數據; 若是slave鏈接到了一個錯誤的master上,好比故障轉移以後,那麼哨兵會確保它們鏈接到正確的master上。
若是一個master被認爲odown了,並且majority哨兵都容許了主備切換,那麼某個哨兵就會執行主備切換操做,此時首先要選舉一個slave來。會考慮slave的一些信息:
(1)跟master斷開鏈接的時長。
(2)slave優先級。
(3)複製offset。
(4)run id。
若是一個slave跟master斷開鏈接已經超過了down-after-milliseconds的10倍,外加master宕機的時長,那麼slave就被認爲不適合選舉爲master:
(down-after-milliseconds * 10) +milliseconds_since_master_is_in_SDOWN_state
接下來會對slave進行排序:
(1)按照slave優先級進行排序,slave priority越低,優先級就越高。
(2)若是slave priority相同,那麼看replica offset,哪一個slave複製了越多的數據,offset越靠後,優先級就越高。
(3)若是上面兩個條件都相同,那麼選擇一個run id比較小的那個slave。
每次一個哨兵要作主備切換,首先須要quorum數量的哨兵認爲odown,而後選舉出一個哨兵來作切換,這個哨兵還得獲得majority哨兵的受權,才能正式執行切換。若是quorum < majority,好比5個哨兵,majority就是3,quorum設置爲2,那麼就3個哨兵受權就能夠執行切換。可是若是quorum >= majority,那麼必須quorum數量的哨兵都受權,好比5個哨兵,quorum是5,那麼必須5個哨兵都贊成受權,才能執行切換。
哨兵會對一套redis master+slave進行監控,有相應的監控的配置。執行切換的那個哨兵,會從要切換到的新master(salve->master)那裏獲得一個configuration epoch,這就是一個version號,每次切換的version號都必須是惟一的。若是第一個選舉出的哨兵切換失敗了,那麼其餘哨兵,會等待failover-timeout時間,而後接替繼續執行切換,此時會從新獲取一個新的configuration epoch,做爲新的version號。
哨兵完成切換以後,會在本身本地更新生成最新的master配置,而後同步給其餘的哨兵,就是經過以前說的pub/sub消息機制。這裏以前的version號就很重要了,由於各類消息都是經過一個channel去發佈和監聽的,因此一個哨兵完成一次新的切換以後,新的master配置是跟着新的version號的。其餘的哨兵都是根據版本號的大小來更新本身的master配置的。