Redis Sentinel 詳解

Redis Sentinel Documentation

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

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

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

雖然 Redis Sentinel 釋出爲一個單獨的可執行文件 redis-sentinel , 但實際上它只是一個運行在特殊模式下的 Redis 服務器, 你能夠在啓動一個普通 Redis 服務器時經過給定 –sentinel 選項來啓動 Redis Sentinel 。redis

獲取 Sentinel

目前 Sentinel 系統是 Redis 的 unstable 分支的一部分, 你必須到 Redis 項目的 Github 頁面 克隆一份 unstable 分支, 而後經過編譯來得到 Sentinel 系統。算法

Sentinel 程序能夠在編譯後的 src 文檔中發現, 它是一個命名爲 redis-sentinel 的程序。安全

你也能夠經過下一節介紹的方法, 讓 redis-server 程序運行在 Sentinel 模式之下。服務器

另外, 一個新版本的 Sentinel 已經包含在了 Redis 2.8.0 版本的釋出文件中。網絡

啓動 Sentinel

對於 redis-sentinel 程序, 你能夠用如下命令來啓動 Sentinel 系統:架構

redis-sentinel /path/to/sentinel.conf

對於 redis-server 程序, 你能夠用如下命令來啓動一個運行在 Sentinel 模式下的 Redis 服務器:分佈式

redis-server /path/to/sentinel.conf --sentinel

兩種方法均可以啓動一個 Sentinel 實例。spa

啓動 Sentinel 實例必須指定相應的配置文件, 系統會使用配置文件來保存 Sentinel 的當前狀態, 並在 Sentinel 重啓時經過載入配置文件來進行狀態還原。

若是啓動 Sentinel 時沒有指定相應的配置文件, 或者指定的配置文件不可寫(not writable), 那麼 Sentinel 會拒絕啓動。

配置 Sentinel

Redis 源碼中包含了一個名爲 sentinel.conf 的文件, 這個文件是一個帶有詳細註釋的 Sentinel 配置文件示例。

運行一個 Sentinel 所需的最少配置以下所示:

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1

sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5

第一行配置指示 Sentinel 去監視一個名爲 mymaster 的主服務器, 這個主服務器的 IP 地址爲 127.0.0.1 , 端口號爲 6379 , 而將這個主服務器判斷爲失效至少須要 2 個 Sentinel 贊成 (只要贊成 Sentinel 的數量不達標,自動故障遷移就不會執行)。

不過要注意, 不管你設置要多少個 Sentinel 贊成才能判斷一個服務器失效, 一個 Sentinel 都須要得到系統中多數(majority) Sentinel 的支持, 才能發起一次自動故障遷移, 並預留一個給定的配置紀元 (configuration Epoch ,一個配置紀元就是一個新主服務器配置的版本號)。

換句話說, 在只有少數(minority) Sentinel 進程正常運做的狀況下, Sentinel 是不能執行自動故障遷移的。

其餘選項的基本格式以下:

sentinel <選項的名字> <主服務器的名字> <選項的值>

各個選項的功能以下:

  • down-after-milliseconds 選項指定了 Sentinel 認爲服務器已經斷線所需的毫秒數。

若是服務器在給定的毫秒數以內, 沒有返回 Sentinel 發送的 PING 命令的回覆, 或者返回一個錯誤, 那麼 Sentinel 將這個服務器標記爲主觀下線(subjectively down,簡稱 SDOWN )。

不過只有一個 Sentinel 將服務器標記爲主觀下線並不必定會引發服務器的自動故障遷移: 只有在足夠數量的 Sentinel 都將一個服務器標記爲主觀下線以後, 服務器纔會被標記爲客觀下線(objectively down, 簡稱 ODOWN ), 這時自動故障遷移纔會執行。

將服務器標記爲客觀下線所需的 Sentinel 數量由對主服務器的配置決定。

  • parallel-syncs 選項指定了在執行故障轉移時, 最多能夠有多少個從服務器同時對新的主服務器進行同步, 這個數字越小, 完成故障轉移所需的時間就越長。

若是從服務器被設置爲容許使用過時數據集(參見對 redis.conf 文件中對 slave-serve-stale-data 選項的說明), 那麼你可能不但願全部從服務器都在同一時間向新的主服務器發送同步請求, 由於儘管複製過程的絕大部分步驟都不會阻塞從服務器, 但從服務器在載入主服務器發來的 RDB 文件時, 仍然會形成從服務器在一段時間內不能處理命令請求: 若是所有從服務器一塊兒對新的主服務器進行同步, 那麼就可能會形成全部從服務器在短期內所有不可用的狀況出現。

你能夠經過將這個值設爲 1 來保證每次只有一個從服務器處於不能處理命令請求的狀態。

本文檔剩餘的內容將對 Sentinel 系統的其餘選項進行介紹, 示例配置文件 sentinel.conf 也對相關的選項進行了完整的註釋。

主觀下線和客觀下線

前面說過, Redis 的 Sentinel 中關於下線(down)有兩個不一樣的概念:

  • 主觀下線(Subjectively Down, 簡稱 SDOWN)指的是單個 Sentinel 實例對服務器作出的下線判斷。
  • 客觀下線(Objectively Down, 簡稱 ODOWN)指的是多個 Sentinel 實例在對同一個服務器作出 SDOWN 判斷, 而且經過 SENTINEL is-master-down-by-addr 命令互相交流以後, 得出的服務器下線判斷。 (一個 Sentinel 能夠經過向另外一個 Sentinel 發送 SENTINEL is-master-down-by-addr 命令來詢問對方是否定爲給定的服務器已下線。)

若是一個服務器沒有在 master-down-after-milliseconds 選項所指定的時間內, 對向它發送 PING 命令的 Sentinel 返回一個有效回覆(valid reply), 那麼 Sentinel 就會將這個服務器標記爲主觀下線。

服務器對 PING 命令的有效回覆能夠是如下三種回覆的其中一種:

  • 返回 +PONG 。
  • 返回 -LOADING 錯誤。
  • 返回 -MASTERDOWN 錯誤。

若是服務器返回除以上三種回覆以外的其餘回覆, 又或者在指定時間內沒有回覆 PING 命令, 那麼 Sentinel 認爲服務器返回的回覆無效(non-valid)。

注意, 一個服務器必須在 master-down-after-milliseconds 毫秒內, 一直返回無效回覆纔會被 Sentinel 標記爲主觀下線。

舉個例子, 若是 master-down-after-milliseconds 選項的值爲 30000 毫秒(30 秒), 那麼只要服務器能在每 29 秒以內返回至少一次有效回覆, 這個服務器就仍然會被認爲是處於正常狀態的。

從主觀下線狀態切換到客觀下線狀態並無使用嚴格的法定人數算法(strong quorum algorithm), 而是使用了流言協議: 若是 Sentinel 在給定的時間範圍內, 從其餘 Sentinel 那裏接收到了足夠數量的主服務器下線報告, 那麼 Sentinel 就會將主服務器的狀態從主觀下線改變爲客觀下線。 若是以後其餘 Sentinel 再也不報告主服務器已下線, 那麼客觀下線狀態就會被移除。

客觀下線條件只適用於主服務器: 對於任何其餘類型的 Redis 實例, Sentinel 在將它們判斷爲下線前不須要進行協商, 因此從服務器或者其餘 Sentinel 永遠不會達到客觀下線條件。

只要一個 Sentinel 發現某個主服務器進入了客觀下線狀態, 這個 Sentinel 就可能會被其餘 Sentinel 推選出, 並對失效的主服務器執行自動故障遷移操做。

每一個 Sentinel 都須要按期執行的任務

  • 每一個 Sentinel 以每秒鐘一次的頻率向它所知的主服務器、從服務器以及其餘 Sentinel 實例發送一個 PING 命令。
  • 若是一個實例(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 那麼這個實例會被 Sentinel 標記爲主觀下線。 一個有效回覆能夠是: +PONG 、 -LOADING 或者 -MASTERDOWN 。
  • 若是一個主服務器被標記爲主觀下線, 那麼正在監視這個主服務器的全部 Sentinel 要以每秒一次的頻率確認主服務器的確進入了主觀下線狀態。
  • 若是一個主服務器被標記爲主觀下線, 而且有足夠數量的 Sentinel (至少要達到配置文件指定的數量)在指定的時間範圍內贊成這一判斷, 那麼這個主服務器被標記爲客觀下線。
  • 在通常狀況下, 每一個 Sentinel 會以每 10 秒一次的頻率向它已知的全部主服務器和從服務器發送 INFO 命令。 當一個主服務器被 Sentinel 標記爲客觀下線時, Sentinel 向下線主服務器的全部從服務器發送 INFO 命令的頻率會從 10 秒一次改成每秒一次。
  • 當沒有足夠數量的 Sentinel 贊成主服務器已經下線, 主服務器的客觀下線狀態就會被移除。 當主服務器從新向 Sentinel 的 PING 命令返回有效回覆時, 主服務器的主觀下線狀態就會被移除。

自動發現 Sentinel 和從服務器

一個 Sentinel 能夠與其餘多個 Sentinel 進行鏈接, 各個 Sentinel 之間能夠互相檢查對方的可用性, 並進行信息交換。

你無須爲運行的每一個 Sentinel 分別設置其餘 Sentinel 的地址, 由於 Sentinel 能夠經過發佈與訂閱功能來自動發現正在監視相同主服務器的其餘 Sentinel , 這一功能是經過向頻道 sentinel:hello 發送信息來實現的。

與此相似, 你也沒必要手動列出主服務器屬下的全部從服務器, 由於 Sentinel 能夠經過詢問主服務器來得到全部從服務器的信息。

  • 每一個 Sentinel 會以每兩秒一次的頻率, 經過發佈與訂閱功能, 向被它監視的全部主服務器和從服務器的 sentinel:hello 頻道發送一條信息, 信息中包含了 Sentinel 的 IP 地址、端口號和運行 ID (runid)。
  • 每一個 Sentinel 都訂閱了被它監視的全部主服務器和從服務器的 sentinel:hello 頻道, 查找以前未出現過的 sentinel (looking for unknown sentinels)。 當一個 Sentinel 發現一個新的 Sentinel 時, 它會將新的 Sentinel 添加到一個列表中, 這個列表保存了 Sentinel 已知的, 監視同一個主服務器的全部其餘 Sentinel 。
  • Sentinel 發送的信息中還包括完整的主服務器當前配置(configuration)。 若是一個 Sentinel 包含的主服務器配置比另外一個 Sentinel 發送的配置要舊, 那麼這個 Sentinel 會當即升級到新配置上。
  • 在將一個新 Sentinel 添加到監視主服務器的列表上面以前, Sentinel 會先檢查列表中是否已經包含了和要添加的 Sentinel 擁有相同運行 ID 或者相同地址(包括 IP 地址和端口號)的 Sentinel , 若是是的話, Sentinel 會先移除列表中已有的那些擁有相同運行 ID 或者相同地址的 Sentinel , 而後再添加新 Sentinel 。

Sentinel API

在默認狀況下, Sentinel 使用 TCP 端口 26379 (普通 Redis 服務器使用的是 6379 )。

Sentinel 接受 Redis 協議格式的命令請求, 因此你可使用 redis-cli 或者任何其餘 Redis 客戶端來與 Sentinel 進行通信。

有兩種方式能夠和 Sentinel 進行通信:

  • 第一種方法是經過直接發送命令來查詢被監視 Redis 服務器的當前狀態, 以及 Sentinel 所知道的關於其餘 Sentinel 的信息, 諸如此類。
  • 另外一種方法是使用發佈與訂閱功能, 經過接收 Sentinel 發送的通知: 當執行故障轉移操做, 或者某個被監視的服務器被判斷爲主觀下線或者客觀下線時, Sentinel 就會發送相應的信息。

Sentinel 命令

如下列出的是 Sentinel 接受的命令:

  • PING :返回 PONG 。
  • sentinel masters :列出全部被監視的主服務器,以及這些主服務器的當前狀態。
  • sentinel slaves [mymaster]:列出給定主服務器的全部從服務器,以及這些從服務器的當前狀態,須要mymaster名字參數。
  • sentinel get-master-addr-by-name [mymaster]: 返回給定名字的主服務器的 IP 地址和端口號。 若是這個主服務器正在執行故障轉移操做, 或者針對這個主服務器的故障轉移操做已經完成, 那麼這個命令返回新的主服務器的 IP 地址和端口號,須要mymaster名字參數。
  • sentinel reset : 重置全部名字和給定模式 pattern 相匹配的主服務器。 pattern 參數是一個 Glob 風格的模式。 重置操做清除主服務器目前的全部狀態, 包括正在執行中的故障轉移, 並移除目前已經發現和關聯的, 主服務器的全部從服務器和 Sentinel 。
  • sentinel failover : 當主服務器失效時, 在不詢問其餘 Sentinel 意見的狀況下, 強制開始一次自動故障遷移 (不過發起故障轉移的 Sentinel 會向其餘 Sentinel 發送一個新的配置,其餘 Sentinel 會根據這個配置進行相應的更新)。

發佈與訂閱信息

客戶端能夠將 Sentinel 看做是一個只提供了訂閱功能的 Redis 服務器: 你不可使用 PUBLISH 命令向這個服務器發送信息, 但你能夠用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 經過訂閱給定的頻道來獲取相應的事件提醒。

一個頻道可以接收和這個頻道的名字相同的事件。 好比說, 名爲 +sdown 的頻道就能夠接收全部實例進入主觀下線(SDOWN)狀態的事件。

經過執行 PSUBSCRIBE * 命令能夠接收全部事件信息。注意, 當信息中包含 instance details 字樣時, 表示頻道所返回的信息中包含了如下用於識別目標實例的內容:

<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>

@ 字符以後的內容用於指定主服務器, 這些內容是可選的, 它們僅在 @ 字符以前的內容指定的實例不是主服務器時使用。

能夠訂閱的頻道以下:

  • +reset-master :主服務器已被重置。
  • +slave :一個新的從服務器已經被 Sentinel 識別並關聯。
  • +failover-state-reconf-slaves :故障轉移狀態切換到了 reconf-slaves 狀態。
  • +failover-detected :另外一個 Sentinel 開始了一次故障轉移操做,或者一個從服務器轉換成了主服務器。
  • +slave-reconf-sent :領頭(leader)的 Sentinel 向實例發送了 [SLAVEOF](/commands/slaveof.html) 命令,爲實例設置新的主服務器。
  • +slave-reconf-inprog :實例正在將本身設置爲指定主服務器的從服務器,但相應的同步過程仍未完成。
  • +slave-reconf-done :從服務器已經成功完成對新主服務器的同步。
  • -dup-sentinel :對給定主服務器進行監視的一個或多個 Sentinel 已經由於重複出現而被移除 —— 當 Sentinel 實例重啓的時候,就會出現這種狀況。
  • +sentinel :一個監視給定主服務器的新 Sentinel 已經被識別並添加。
  • +sdown :給定的實例如今處於主觀下線狀態。
  • -sdown :給定的實例已經再也不處於主觀下線狀態。
  • +odown :給定的實例如今處於客觀下線狀態。
  • -odown :給定的實例已經再也不處於客觀下線狀態。
  • +new-epoch :當前的紀元(epoch)已經被更新。
  • +try-failover :一個新的故障遷移操做正在執行中,等待被大多數 Sentinel 選中(waiting to be elected by the majority)。
  • +elected-leader :贏得指定紀元的選舉,能夠進行故障遷移操做了。
  • +failover-state-select-slave :故障轉移操做如今處於 select-slave 狀態 —— Sentinel 正在尋找能夠升級爲主服務器的從服務器。
  • no-good-slave :Sentinel 操做未能找到適合進行升級的從服務器。Sentinel 會在一段時間以後再次嘗試尋找合適的從服務器來進行升級,又或者直接放棄執行故障轉移操做。
  • selected-slave :Sentinel 順利找到適合進行升級的從服務器。
  • failover-state-send-slaveof-noone :Sentinel 正在將指定的從服務器升級爲主服務器,等待升級功能完成。
  • failover-end-for-timeout :故障轉移由於超時而停止,不過最終全部從服務器都會開始複製新的主服務器(slaves will eventually be configured to replicate with the new master anyway)。
  • failover-end :故障轉移操做順利完成。全部從服務器都開始複製新的主服務器了。
  • +switch-master :配置變動,主服務器的 IP 和地址已經改變。 這是絕大多數外部用戶都關心的信息。
  • +tilt :進入 tilt 模式。
  • -tilt :退出 tilt 模式。

故障轉移

一次故障轉移操做由如下步驟組成:

  • 發現主服務器已經進入客觀下線狀態。
  • 對咱們的當前紀元進行自增(詳情請參考 Raft leader election ), 並嘗試在這個紀元中當選。
  • 若是當選失敗, 那麼在設定的故障遷移超時時間的兩倍以後, 從新嘗試當選。 若是當選成功, 那麼執行如下步驟。
  • 選出一個從服務器,並將它升級爲主服務器。
  • 向被選中的從服務器發送 SLAVEOF NO ONE 命令,讓它轉變爲主服務器。
  • 經過發佈與訂閱功能, 將更新後的配置傳播給全部其餘 Sentinel , 其餘 Sentinel 對它們本身的配置進行更新。
  • 向已下線主服務器的從服務器發送 SLAVEOF 命令, 讓它們去複製新的主服務器。
  • 當全部從服務器都已經開始複製新的主服務器時, 領頭 Sentinel 終止此次故障遷移操做。

每當一個 Redis 實例被從新配置(reconfigured) —— 不管是被設置成主服務器、從服務器、又或者被設置成其餘主服務器的從服務器 —— Sentinel 都會向被從新配置的實例發送一個 CONFIG REWRITE 命令, 從而確保這些配置會持久化在硬盤裏。

Sentinel 使用如下規則來選擇新的主服務器:

  • 在失效主服務器屬下的從服務器當中, 那些被標記爲主觀下線、已斷線、或者最後一次回覆 PING 命令的時間大於五秒鐘的從服務器都會被淘汰。
  • 在失效主服務器屬下的從服務器當中, 那些與失效主服務器鏈接斷開的時長超過 down-after 選項指定的時長十倍的從服務器都會被淘汰。
  • 在經歷了以上兩輪淘汰以後剩下來的從服務器中, 咱們選出複製偏移量(replication offset)最大的那個從服務器做爲新的主服務器; 若是複製偏移量不可用, 或者從服務器的複製偏移量相同, 那麼帶有最小運行 ID 的那個從服務器成爲新的主服務器。

關於sentinel leader選舉和failover的詳細過程,參見以下,

1) Leader選舉:

    其實在sentinels故障轉移中,仍然須要一個「Leader」來調度整個過程:master的選舉以及slave的重配置和同步。當集羣中有多個sentinel實例時,如何選舉其中一個sentinel爲leader呢?

    在配置文件中「can-failover」「quorum」參數,以及「is-master-down-by-addr」指令配合來完成整個過程。

    A) 「can-failover」用來代表當前sentinel是否能夠參與「failover」過程,若是爲「YES」則代表它將有能力參與「Leader」的選舉,不然它將做爲「Observer」,observer參與leader選舉投票但不能被選舉;

    B) 「quorum」不只用來控制master ODOWN狀態確認,同時還用來選舉leader時最小「贊同票」數;

    C) 「is-master-down-by-addr」,在上文中以及提到,它能夠用來檢測「ip + port」的master是否已經處於SDOWN狀態,不過此指令不只可以得到master是否處於SDOWN,同時它還額外的返回當前sentinel本地「投票選舉」的Leader信息(runid);

    每一個sentinel實例都持有其餘的sentinels信息,在Leader選舉過程當中(當爲leader的sentinel實例失效時,有可能master server並沒失效,注意分開理解),sentinel實例將從全部的sentinels集合中去除「can-failover = no」和狀態爲SDOWN的sentinels,在剩餘的sentinels列表中按照runid按照「字典」順序排序後,取出runid最小的sentinel實例,並將它「投票選舉」爲Leader,並在其餘sentinel發送的「is-master-down-by-addr」指令時將推選的runid追加到響應中。每一個sentinel實例都會檢測「is-master-down-by-addr」的響應結果,若是「投票選舉」的leader爲本身,且狀態正常的sentinels實例中,「贊同者」的本身的sentinel個數不小於(>=) 50% + 1,且不小與<quorum>,那麼此sentinel就會認爲選舉成功且leader爲本身。

    在sentinel.conf文件中,咱們指望有足夠多的sentinel實例配置「can-failover yes」,這樣可以確保當leader失效時,可以選舉某個sentinel爲leader,以便進行failover。若是leader沒法產生,好比較少的sentinels實例有效,那麼failover過程將沒法繼續.

 

    2) failover過程:

    在Leader觸發failover以前,首先wait數秒(隨即0~5),以便讓其餘sentinel實例準備和調整(有可能多個leader??),若是一切正常,那麼leader就須要開始將一個salve提高爲master,此slave必須爲狀態良好(不能處於SDOWN/ODOWN狀態)且權重值最低(redis.conf中)的,當master身份被確認後,開始failover

    A)「+failover-triggered」: Leader開始進行failover,此後緊跟着「+failover-state-wait-start」,wait數秒。

    B)「+failover-state-select-slave」: Leader開始查找合適的slave

    C)「+selected-slave」: 已經找到合適的slave

    D) 「+failover-state-sen-slaveof-noone」: Leader向slave發送「slaveof no one」指令,此時slave已經完成角色轉換,此slave即爲master

    E) 「+failover-state-wait-promotition」: 等待其餘sentinel確認slave

    F)「+promoted-slave」:確認成功

    G)「+failover-state-reconf-slaves」: 開始對slaves進行reconfig操做。

    H)「+slave-reconf-sent」:向指定的slave發送「slaveof」指令,告知此slave跟隨新的master

    I)「+slave-reconf-inprog」: 此slave正在執行slaveof + SYNC過程,如過slave收到「+slave-reconf-sent」以後將會執行slaveof操做。

    J)「+slave-reconf-done」: 此slave同步完成,此後leader能夠繼續下一個slave的reconfig操做。循環G)

    K)「+failover-end」: 故障轉移結束

    L)「+switch-master」:故障轉移成功後,各個sentinel實例開始監控新的master。

Sentinel 自動故障遷移的一致性特質

Sentinel 自動故障遷移使用 Raft 算法來選舉領頭(leader) Sentinel , 從而確保在一個給定的紀元(epoch)裏, 只有一個領頭產生。

這表示在同一個紀元中, 不會有兩個 Sentinel 同時被選中爲領頭, 而且各個 Sentinel 在同一個紀元中只會對一個領頭進行投票。

更高的配置紀元老是優於較低的紀元, 所以每一個 Sentinel 都會主動使用更新的紀元來代替本身的配置。

簡單來講, 咱們能夠將 Sentinel 配置看做是一個帶有版本號的狀態。 一個狀態會以最後寫入者勝出(last-write-wins)的方式(也便是,最新的配置老是勝出)傳播至全部其餘 Sentinel 。

舉個例子, 當出現網絡分割(network partitions)時, 一個 Sentinel 可能會包含了較舊的配置, 而當這個 Sentinel 接到其餘 Sentinel 發來的版本更新的配置時, Sentinel 就會對本身的配置進行更新。

若是要在網絡分割出現的狀況下仍然保持一致性, 那麼應該使用 min-slaves-to-write 選項, 讓主服務器在鏈接的從實例少於給定數量時中止執行寫操做, 與此同時, 應該在每一個運行 Redis 主服務器或從服務器的機器上運行 Redis Sentinel 進程。

Sentinel 狀態的持久化

Sentinel 的狀態會被持久化在 Sentinel 配置文件裏面。

每當 Sentinel 接收到一個新的配置, 或者當領頭 Sentinel 爲主服務器建立一個新的配置時, 這個配置會與配置紀元一塊兒被保存到磁盤裏面。

這意味着中止和重啓 Sentinel 進程都是安全的。

Sentinel 在非故障遷移的狀況下對實例進行從新配置

即便沒有自動故障遷移操做在進行, Sentinel 總會嘗試將當前的配置設置到被監視的實例上面。 特別是:

  • 根據當前的配置, 若是一個從服務器被宣告爲主服務器, 那麼它會代替原有的主服務器, 成* 爲新的主服務器, 而且成爲原有主服務器的全部從服務器的複製對象。 那些鏈接了錯誤主服務器的從服務器會被從新配置, 使得這些從服務器會去複製正確的主服務器。

不過, 在以上這些條件知足以後, Sentinel 在對實例進行從新配置以前仍然會等待一段足夠長的時間, 確保能夠接收到其餘 Sentinel 發來的配置更新, 從而避免自身由於保存了過時的配置而對實例進行了沒必要要的從新配置。

TILT 模式

Redis Sentinel 嚴重依賴計算機的時間功能: 好比說, 爲了判斷一個實例是否可用, Sentinel 會記錄這個實例最後一次相應 PING 命令的時間, 並將這個時間和當前時間進行對比, 從而知道這個實例有多長時間沒有和 Sentinel 進行任何成功通信。

不過, 一旦計算機的時間功能出現故障, 或者計算機很是忙碌, 又或者進程由於某些緣由而被阻塞時, Sentinel 可能也會跟着出現故障。

TILT 模式是一種特殊的保護模式: 當 Sentinel 發現系統有些不對勁時, Sentinel 就會進入 TILT 模式。

由於 Sentinel 的時間中斷器默認每秒執行 10 次, 因此咱們預期時間中斷器的兩次執行之間的間隔爲 100 毫秒左右。 Sentinel 的作法是, 記錄上一次時間中斷器執行時的時間, 並將它和這一次時間中斷器執行的時間進行對比:

  • 若是兩次調用時間之間的差距爲負值, 或者很是大(超過 2 秒鐘), 那麼 Sentinel 進入 TILT 模式。
  • 若是 Sentinel 已經進入 TILT 模式, 那麼 Sentinel 延遲退出 TILT 模式的時間。

當 Sentinel 進入 TILT 模式時, 它仍然會繼續監視全部目標, 可是:

  • 它再也不執行任何操做,好比故障轉移。
  • 當有實例向這個 Sentinel 發送 SENTINEL is-master-down-by-addr 命令時, Sentinel 返回負值: 由於這個 Sentinel 所進行的下線判斷已經再也不準確。

若是 TILT 能夠正常維持 30 秒鐘, 那麼 Sentinel 退出 TILT 模式。

處理 -BUSY 狀態

當 Lua 腳本的運行時間超過指定時限時, Redis 就會返回 -BUSY 錯誤。

當出現這種狀況時, Sentinel 在嘗試執行故障轉移操做以前, 會先向服務器發送一個 SCRIPT KILL 命令, 若是服務器正在執行的是一個只讀腳本的話, 那麼這個腳本就會被殺死, 服務器就會回到正常狀態。

 

附:

一.Sentinel.conf詳解

##sentinel實例之間的通信端口  
##redis-0  
port 26379  
##sentinel須要監控的master信息:<mastername> <masterIP> <masterPort> <quorum>  
##<quorum>應該小於集羣中slave的個數,只有當至少<quorum>個sentinel實例提交"master失效"  
##纔會認爲master爲O_DWON("客觀"失效)  
sentinel monitor def_master 127.0.0.1 6379 2  
  
sentinel auth-pass def_master 012_345^678-90  
  
##master被當前sentinel實例認定爲「失效」的間隔時間  
##若是當前sentinel與master直接的通信中,在指定時間內沒有響應或者響應錯誤代碼,那麼  
##當前sentinel就認爲master失效(SDOWN,「主觀」失效)  
##<mastername> <millseconds>  
##默認爲30秒  
sentinel down-after-milliseconds def_master 30000  
  
##當前sentinel實例是否容許實施「failover」(故障轉移)  
##no表示當前sentinel爲「觀察者」(只參與"投票".不參與實施failover),  
##全局中至少有一個爲yes  
sentinel can-failover def_master yes  
  
##當新master產生時,同時進行「slaveof」到新master並進行「SYNC」的slave個數。  
##默認爲1,建議保持默認值  
##在salve執行salveof與同步時,將會終止客戶端請求。  
##此值較大,意味着「集羣」終止客戶端請求的時間總和和較大。  
##此值較小,意味着「集羣」在故障轉移期間,多個salve向客戶端提供服務時仍然使用舊數據。  
sentinel parallel-syncs def_master 1  
  
##failover過時時間,當failover開始後,在此時間內仍然沒有觸發任何failover操做,  
##當前sentinel將會認爲這次failoer失敗。  
sentinel failover-timeout def_master 900000  
  
##當failover時,能夠指定一個「通知」腳本用來告知系統管理員,當前集羣的狀況。  
##腳本被容許執行的最大時間爲60秒,若是超時,腳本將會被終止(KILL)  
##腳本執行的結果:  
## 1 -> 稍後重試,最大重試次數爲10;   
## 2 -> 執行結束,無需重試  
##sentinel notification-script mymaster /var/redis/notify.sh  
  
##failover以後重配置客戶端,執行腳本時會傳遞大量參數,請參考相關文檔  
# sentinel client-reconfig-script <master-name> <script-path>  

更詳細信息,請參考src/sentinel.c源碼 .配置文件加載過程參見方法:sentinelHandlerConfiguration(..)

2、Jedis客戶端與Setinel

Java代碼

Set<String> sentinels = new HashSet<String>(16);  
sentinels.add("127.0.0.1:26379");//集羣中全部sentinels的地址  
sentinels.add("127.0.0.1:26479");  
sentinels.add("127.0.0.1:26579");  
GenericObjectPoolConfig config = new GenericObjectPoolConfig();  
config.setMaxTotal(32);  
//setinel客戶端提供了master自動發現功能  
JedisSentinelPool jedisSentinelPool = new JedisSentinelPool("def_master",
sentinels,config, "012_345^678-90");  
Jedis jedis = jedisSentinelPool.getResource();  
try{  
    //  
    jedis.set("key","value");  
} finally {  
    jedisSentinelPool.returnResource(jedis);  
}  
jedisSentinelPool.close();  

JedisSentinelPool將遍歷sentinels列表,並嘗試與每一個sentinel創建鏈接直到成功爲止;若是創建鏈接成功,就向此sentinel發送「get-master-addr-by-name」指令,獲取master的位置,此後將創建與master的鏈接。此後JedisSentinelPool還會啓動一個監測線程,用於監測master的存活狀況,若是master角色遷移,則從新獲取新的master地址,並從新初始化鏈接池。注意JedisSentinelPool並無提供「M-S」下讀寫分離的設計,即讀寫操做均在master上發生。不過很遺憾,我以爲仍是須要一種客戶端解決方案,可以實現讀寫分離。

相關文章
相關標籤/搜索