Redis詳解(六)——哨兵機制

Redis詳解(六)——哨兵機制

1、概述

Redis Sentinel是一個分佈式系統,爲Redis提供高可用性解決方案。能夠在一個架構中運行多個 Sentinel 進程(progress), 這些進程使用流言協議(gossip protocols)來 接收關於主服務器是否下線的信息, 並使用投票協議(agreement protocols)來決定是否執行自動故 障遷移, 以及選擇哪一個從服務器做爲新的主服務器。html

Redis 的 Sentinel 系統用於管理多個 Redis 服務器(instance) 該系統執行如下三個任務:redis

  • 監控(Monitoring): Sentinel 會不斷地按期檢查你的主服務器和從服務器是否運做正常。
  • 提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 能夠經過 API 向管理員或者其餘應用程序發送通知。
  • 自動故障遷移(Automaticfailover): 當一個主服務器不能正常工做時, Sentinel 會開始一次自動故障遷移操做, 它會將失效主服務器的其中 一個從服務器升級爲新的主服務器, 並讓失效主服務器的其餘從服務器改成複製新的主服務器; 當客 戶端試圖鏈接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址, 使得集羣可使用新主 服務器代替失效服務器。

2、Sentinel 工做原理分析

(1)哨兵文件詳解

配置一:sentinel monitor <master-name> <ip> <port> <quorum>數據庫

這個配置表達的是 哨兵節點按期監控 名字叫作 <master-name> 而且 IP 爲 <ip> 端口號爲 <port> 的主節點。<quorum> 表示的是哨兵判斷主節點是否發生故障的票數。也就是說若是咱們將<quorum>設置爲2就表明至少要有兩個哨兵認爲主節點故障了,纔算這個主節點是客觀下線的了,通常是設置爲sentinel節點數的一半加一。數組

配置二:sentinel down-after-milliseconds <master-name> <times>服務器

每一個哨兵節點會按期發送ping命令來判斷Redis節點和其他的哨兵節點是不是可達的,若是超過了配置的<times>時間沒有收到pong回覆,就主觀判斷節點是不可達的,<times>的單位爲毫秒。網絡

配置三:sentinel parallel-syncs <master-name> <nums>數據結構

當哨兵節點都認爲主節點故障時,哨兵投票選出的leader會進行故障轉移,選出新的主節點,原來的從節點們會向新的主節點發起復制,這個配置就是控制在故障轉移以後,每次能夠向新的主節點發起復制的節點的個數,最多爲<nums>個,由於若是不加控制會對主節點的網絡和磁盤IO資源很大的開銷。架構

配置四:sentinel failover-timeout <master-name> <times>分佈式

這個表明哨兵進行故障轉移時若是超過了配置的<times>時間就表示故障轉移超時失敗。3d

配置五: sentinel auth-pass <master-name> <password>

若是主節點設置了密碼,則須要這個配置,不然哨兵沒法對主節點進行監控。

(2)爲何要用到哨兵

哨兵(Sentinel)主要是爲了解決在主從複製架構中出現宕機的狀況,主要分爲兩種狀況:

1).從Redis宕機

這個相對而言比較簡單,在Redis中從庫從新啓動後會自動加入到主從架構中,自動完成同步數據。在Redis2.8版本後,主從斷線後恢復的狀況下實現增量複製。

2).主Redis宕機

這個相對而言就會複雜一些,須要如下2步才能完成

a. 在從數據庫中執行SLAVEOF NO ONE命令,斷開主從關係而且提高爲主庫繼續服務

b. 第二步,將主庫從新啓動後,執行SLAVEOF命令,將其設置爲其餘庫的從庫,這時數據就能更新回來

因爲這個手動完成恢復的過程實際上是比較麻煩的而且容易出錯,因此Redis提供的哨兵(sentinel)的功能來解決

(3)哨兵機制(sentinel)的高可用

Sentinel(哨兵)是Redis 的高可用性解決方案:由一個或多個Sentinel 實例 組成的Sentinel 系統能夠監視任意多個主服務器,以及這些主服務器屬下的全部從服務器,並在被監視的主服務器進入下線狀態時,自動將下線主服務器屬下的某個從服務器升級爲新的主服務器。

如圖所示

img

在Server1 掉線後:

img

升級Server2 爲新的主服務器:

img

(4)哨兵的定時監控

任務1:每一個哨兵節點每10秒會向主節點和從節點發送info命令獲取最拓撲結構圖,哨兵配置時只要配置對主節點的監控便可,經過向主節點發送info,獲取從節點的信息,並當有新的從節點加入時能夠立刻感知到

img

任務2:每一個哨兵節點每隔2秒會向redis數據節點的指定頻道上發送該哨兵節點對於主節點的判斷以及當前哨兵節點的信息,同時每一個哨兵節點也會訂閱該頻道,來了解其它哨兵節點的信息及對主節點的判斷,其實就是經過消息publish和subscribe來完成的

img

任務3:每隔1秒每一個哨兵會向主節點、從節點及其他哨兵節點發送一次ping命令作一次心跳檢測,這個也是哨兵用來判斷節點是否正常的重要依據

img

主觀下線:所謂主觀下線,就是單個sentinel認爲某個服務下線(有多是接收不到訂閱,之間的網絡不通等等緣由)。

sentinel會以每秒一次的頻率向全部與其創建了命令鏈接的實例(master,從服務,其餘sentinel)發ping命令,經過判斷ping回覆是有效回覆,仍是無效回覆來判斷實例時候在線(對該sentinel來講是「主觀在線」)。

sentinel配置文件中的down-after-milliseconds設置了判斷主觀下線的時間長度,若是實例在down-after-milliseconds毫秒內,返回的都是無效回覆,那麼sentinel回認爲該實例已(主觀)下線,修改其flags狀態爲SRI_S_DOWN。若是多個sentinel監視一個服務,有可能存在多個sentinel的down-after-milliseconds配置不一樣,這個在實際生產中要注意。

客觀下線:當主觀下線的節點是主節點時,此時該哨兵3節點會經過指令sentinel is-masterdown-by-addr尋求其它哨兵節點對主節點的判斷,若是其餘的哨兵也認爲主節點主觀線下了,則當認爲主觀下線的票數超過了quorum(選舉)個數,此時哨兵節點則認爲該主節點確實有問題,這樣就客觀下線了,大部分哨兵節點都贊成下線操做,也就說是客觀下線

img

(5)哨兵lerder選舉流程

若是主節點被斷定爲客觀下線以後,就要選取一個哨兵節點來完成後面的故障轉移工做,選舉出一個leader的流程以下:

a)每一個在線的哨兵節點均可以成爲領導者,當它確認(好比哨兵3)主節點下線時,會向其它哨兵發is-master-down-by-addr命令,徵求判斷並要求將本身設置爲領導者,由領導者處理故障轉移;
b)當其它哨兵收到此命令時,能夠贊成或者拒絕它成爲領導者;
c)若是哨兵3發現本身在選舉的票數大於等於num(sentinels)/2+1時,將成爲領導者,若是沒有超過,繼續選舉…………

img

(6)自動故障轉移機制

在從節點中選擇新的主節點

sentinel狀態數據結構中保存了主服務的全部從服務信息,領頭sentinel按照以下的規則從從服務列表中挑選出新的主服務

  1. 過濾掉主觀下線的節點
  2. 選擇slave-priority最高的節點,若是由則返回沒有就繼續選擇
  3. 選擇出複製偏移量最大的系節點,由於複製便宜量越大則數據複製的越完整,若是由就返回了,沒有就繼續
  4. 選擇run_id最小的節點

img

更新主從狀態

經過slaveof no one命令,讓選出來的從節點成爲主節點;並經過slaveof命令讓其餘節點成爲其從節點。

將已下線的主節點設置成新的主節點的從節點,當其回覆正常時,複製新的主節點,變成新的主節點的從節點

同理,當已下線的服務從新上線時,sentinel會向其發送slaveof命令,讓其成爲新主的從

3、Sentinel獲取服務器信息

(1) Sentinel獲取主服務器信息

    Sentinel默認會以每10秒一次的頻率,經過命令鏈接向主服務器發送info命令,經過分析info命令的回覆來獲取主服務器的當前信息,就像在上篇講到的複製功能,在客戶端輸入info replication 命令同樣,Sentinel能夠獲取如下兩方面的信息:

    (1) 關於主服務器自己的信息,包括服務器run_id,role的服務器角色。

    (2) 關於全部從服務器的信息,每一個從服務器都由一個slave字符串開頭的行記錄,記錄了從服務器IP和端口(主服務器中有從庫的配置信息)。

(2)Sentinel獲取從服務器信息

    當Sentinel發現主服務器有新的從服務器出現時,Sentinel除了會爲這個新的從服務器建立相應的實例結構(sentinelRedisInstance)以外,Sentinel還會建立鏈接到從服務器的命令鏈接和訂閱鏈接。Sentinel默認會以每10秒一次的頻率經過命令鏈接從服務器發送info命令,經過分析info命令的回覆來獲取從服務器的當前信息。包括:從服務器運行run_ID、從服務器角色role、主服務器的ip及端口、主從服務器的鏈接狀態master_link_status、從服務器的優先級slave_priority。

(3)Sentinel向主從服務器發送信息

    在默認狀況下, Sentinel會以每2秒一次的頻率,經過命令鏈接向全部被監視的主服務器和從服務器發送如下格式的命令:

  img

    這條命令向服務器的_sentinel_:hello頻道發送了一條信息,信息的內容由多個參數組成:

    (1) 以s_開頭以參數記錄的是sentinel自己的信息。

    (2) 而m_開頭的參數記錄的則是主服務器的信息,若是sentinel正在監視的是主服務器,那麼這些參數就是主服務器的信息,若是sentinel正在監視的是從服務器,那麼這些參數記錄就是從服務器正在複製的主服務器的信息。

參數 描述
S_ip Sentinel的ip地址
S_port Sentinel的端口號
S_runid Sentinel的運行ID
S_epoch Sentinel 的當前配置紀元
m_name 主服務器的名字
M_ip 主服務器的IP地址
M_port 主服務器的端口號
M_epoch 主服務器的當前配置紀元

    

如下是一條sentinel經過publish命令向主服務器發送的信息示例:

  img

這個示例中sentinel的ip地址爲172.0.0.1端口號爲26379, 運行ID爲後面一串,當前紀元爲0。主服務器的名字爲mymaster,ip地址爲127.0.0.1,端口號爲6379, 當前紀元爲0。

(4)sentinel接收來自主服務器和從服務器的頻道信息

    當sentinel與一個主服務器或者從服務器創建起訂閱鏈接以後,Sentinel就會經過訂閱鏈接,向服務器發送如下命令:subscribe_sentinel_:hello 。對於每一個與Sentinel鏈接的服務器,Sentinel既經過命令連向服務器的_sentinel_:hello頻道發送信息,又經過訂閱鏈接從服務器的_sentinel_:hello頻道接收信息。

    當有三個sentinel,分別是sentinel一、sentinel2 、sentinel3。三個sentinel在監視同一個服務器,那麼當sentinel1向服務器的_sentinel_:hello頻道發送一條信息時,全部訂閱了_sentinel_:hello頻道的sentinel(包括sentinel1本身在內)都會收到這條信息。

    當一個sentinel從_sentinel_:hello頻道收到一條信息時,sentinel會對這條信息進行分析,提取出信息中sentinel 的 ip 、port、runID等8個參數,並進行如下檢查:

    (1) 若是信息中記錄的sentinel運行ID和接收信息的sentinel運行ID相同,那麼說明這條信息是sentinel本身發送的,sentinel將丟棄這條信息,不作進一步處理。

    (2) 相反地,若是信息中記錄的sentinel運行ID和接收信息的sentinel運行ID不相同,那說明這條信息監視同一個服務器的其它sentinel發來的,接收信息的sentinel將根據信息中的參數,對相應主服務器的實例結構進行更新。

(5)sentinel更新本身的sentinels字典

    sentinel爲主服務器建立實例結構中的sentinels字典,保存了sentinel自己,還監視這個主服務器的其餘sentinel的資料。當一個sentinel接收到其餘sentinels發來的信息時,接收的sentinel會從信息中分析並提取出兩方面參數:

    (1)與sentinel有關的參數,包括sentinel的ip、port、runid、配置紀元。

    (2)與主服務器有關的參數, 包括監視主服務器的ip、port、runid、配置紀元。

    假設分別有三個sentinel: 127.0.0.1:2637九、127.0.0.1:26380、127.0.0.1:26381。三個sentinel正在監視主服務器127.0.0.1:6379, 那麼當127.0.0.1:26379這個sentinel接收到如下消息時:

    img

    這個sentinel將執行如下動做:

    (1) 第一條信息發送者爲本身,信息忽略。

    (2) 第二條信息發送者爲26381, sentinel會根據信息提取出內容,對sentinels字典中26381對應的實例結構進行更新。

    (3) 第三條信息發送者爲23680,一樣更新字典中的23680對應的實例結構。

    每一個sentinel都有本身的一個sentinels字典, 對於26379的sentinel它的sentinels字典信息保存了26380和26381兩個sentinel信息。其它sentinel也同樣。

(6)sentinel建立連向其餘sentinel的命令鏈接

    當sentinel經過頻道信息發現一個新的sentinel時,不只更新sentinels字典,還會建立一個連向sentinel命令鏈接,而新的sentinel也會建立連向這個sentinel的命令鏈接,最終監視同一個主服務器的多個sentinel將造成相互鏈接的網絡。以下圖所示:

img

4、Sentinel的工做原理總結

1):每一個Sentinel以每秒鐘一次的頻率向它所知的Master,Slave以及其餘 Sentinel 實例發送一個 PING 命令。

2):若是一個實例(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個實例會被 Sentinel 標記爲主觀下線。

3):若是一個Master被標記爲主觀下線,則正在監視這個Master的全部 Sentinel 要以每秒一次的頻率確認Master的確進入了主觀下線狀態。

4):當有足夠數量的 Sentinel(大於等於配置文件指定的值)在指定的時間範圍內確認Master的確進入了主觀下線狀態, 則Master會被標記爲客觀下線 。

5):在通常狀況下, 每一個 Sentinel 會以每 10 秒一次的頻率向它已知的全部Master,Slave發送 INFO 命令 。

6):當Master被 Sentinel 標記爲客觀下線時,Sentinel 向下線的 Master 的全部 Slave 發送 INFO 命令的頻率會從 10 秒一次改成每秒一次 。

7):若沒有足夠數量的 Sentinel 贊成 Master 已經下線, Master 的客觀下線狀態就會被移除。

若 Master 從新向 Sentinel 的 PING 命令返回有效回覆, Master 的主觀下線狀態就會被移除。

5、參考資料

http://www.javashuo.com/article/p-wrculwtc-mx.html

相關文章
相關標籤/搜索