分佈性實踐--sentinel哨兵配置

Redis哨兵-實現Redis高可用

轉載自Redis中文網 - Redis哨兵-實現Redis高可用html

概述

Redis哨兵爲Redis提供了高可用性。實際上這意味着你可使用哨兵模式建立一個能夠不用人爲干預而應對各類故障的Redis部署。redis

哨兵模式還提供了其餘的附加功能,如監控,通知,爲客戶端提供配置。 算法

下面是在宏觀層面上哨兵模式的功能列表: 緩存

  • :哨兵不斷的檢查master和slave是否正常的運行。
  • 通知:當監控的某臺Redis實例發生問題時,能夠經過API通知系統管理員和其餘的應用程序。
  • 自動故障轉移:若是一個master不正常運行了,哨兵能夠啓動一個故障轉移進程,將一個slave升級成爲master,其餘的slave被從新配置使用新的master,而且應用程序使用Redis服務端通知的新地址。
  • 配置提供者:哨兵做爲Redis客戶端發現的權威來源:客戶端鏈接到哨兵請求當前可靠的master的地址。若是發生故障,哨兵將報告新地址。

哨兵的分佈式特性 

Redis哨兵是一個分佈式系統: 安全

哨兵自身被設計成和多個哨兵進程一塊兒合做運行。有多個哨兵進程合做的好處有: 服務器

  1. 當多個哨兵對一個master再也不可用達成一致時執行故障檢測。這會下降錯誤判斷的機率。
  2. 即便在不是全部的哨兵都工做時哨兵也會工做,使系統健壯的抵抗故障。畢竟在故障系統裏單點故障沒有什麼意義。

Redis的哨兵、Redis實例(master和slave)、和客戶端是一個有特種功能的大型分佈式系統。在這個文檔裏將逐步從爲了理解哨兵基本性質須要的基礎信息,到爲了理解怎樣正確的使用哨兵工做的更復雜的信息(這是可選的)進行介紹。 網絡

快速入門 

得到哨兵 

當前的哨兵版本是sentinel 2。它是基於最初哨兵的實現,使用更健壯的和更簡單的預算算法(在這個文檔裏有解釋)重寫的。 異步

Redis2.8和Redis3.0附帶穩定的哨兵版本。他們是Redis的兩個最新穩定版本。 分佈式

在不穩定版本的分支上執行新的改進,且有時一些新特性一旦被認爲是穩定的就會被移植到Redis2.8和Redis3.0分支中。 ide

Redis2.6附帶Redis sentinel 1,它是棄用的不建議使用。 

運行哨兵 

若是你使用可執行的 redis-sentinel(或者你有可執行的redis-server),你可使用下面的命令行運行哨兵: 

redis-sentinel /path/to/sentinel.conf

另外你能夠直接使用可執行的redis-server在哨兵模式下啓動。 

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

兩種方式效果都是同樣的。 

然而在啓動哨兵時必須使用一個配置文件,由於這個配置文件將用於系統保存當前狀態和在重啓時從新加載。哨兵會在沒有指定配置文件或指定的配置文件不可寫的時候拒絕啓動。 

Redis 哨兵默認監聽26379 TCP端口,因此爲了哨兵的正常工做,你的26379端口必須開放接收其餘哨兵實例的IP地址的鏈接。不然哨兵不能通訊和商定作什麼,故障轉移將永不會執行。 

部署哨兵以前須要瞭解的基本事情 

  1. 一個健壯的部署至少須要三個哨兵實例。
  2. 三個哨兵實例應該放置在客戶使用獨立方式確認故障的計算機或虛擬機中。例如不一樣的物理機或不一樣可用區域的虛擬機。
  3. sentinel + Redis實例不保證在故障期間保留確認的寫入,由於Redis使用異步複製。然而有方式部署哨兵使丟失數據限制在特定時刻,雖然有更安全的方式部署它。
  4. 你的客戶端要支持哨兵,流行的客戶端都支持哨兵,但不是所有。
  5. 沒有HA設置是安全的,若是你不常常的在開發環境測試,在生產環境他們會更好。你可能會有一個明顯的錯誤配置只是當太晚的時候。
  6. Sentinel,Docker,或者其餘形式的網絡地址交換或端口映射須要加倍當心:Docker執行端口從新映射,破壞Sentinel自動發現其餘的哨兵進程和master的slave列表。稍後在這個文檔裏檢查關於Sentinel和Docker的部分,瞭解更多信息。

配置哨兵 

Redis源碼發佈包包含一個sentinel.conf的文件,它是一個自含的配置文件示例,你可使用它配置哨兵,一個典型的最小的配置文件就像下面的配置: 

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

你只須要指定masters監控,給予每一個分開的master不一樣的名字。不須要指定slaves,它們是自動發現的。Sentinel會自動的更新關於slaves的附加信息(爲了保留信息以防重啓)。每次slave晉升爲一個master或者每次發現新的Sentinel都會重寫配置。 

上面的示例配置中,主要監控兩組Redis示例,每一個由一個master和若干個slave組成。一組實例叫mymaster,另外一組叫 resque。 

sentinel monitor的參數聲明的含義以下所示: 

sentinel monitor [master-group-name] [ip] [port] [quorum]

爲了更清晰,咱們逐行的解釋每一個選項的含義: 

第一行用於告訴Redis監控一個master叫作mymaster,它的地址在127.0.0.1,端口爲6379,法定人數是2。每一個參數都很容易理解,可是quorum須要解釋一下: 

  1. quorum是Sentinel須要協商贊成master是否可到達的數量。爲了真正的標記slave爲失敗,並最終是否須要啓動一個故障轉移進程。
  2. 不管怎樣,quorum只用於檢測故障。爲了實際執行故障轉移,Sentinel須要選舉leader並進行受權。這隻發生在大多數Sentinel進程的選舉。

例如你有5個哨兵進程,而且給定的master的quorum的值設置爲2,這是將發生的事情: 

  1. 若是兩個哨兵進程同時贊成master是不可到達的,這兩個哨兵的其中一個將啓動一個故障轉移。
  2. 若是至少三個哨兵可得到,故障轉移將會被受權並真實的啓動。

實際上這意味着在故障轉移期間若是大多數的Sentinel進程不能通訊,Sentinel將會永不啓動故障轉移(即在少數分區沒有故障轉移)。 

其餘Sentinel選項 

其餘的選項一般是這種形式: 

sentinel [option_name] [master_name] [option_value]

而且用於下面的目的: 

  • down-after-milliseconds - 一個實例不可到達(不能ping通或者有錯誤),Sentinel開始認爲它是down的毫秒數。
  • parallel-syncs - 設置在故障轉移以後同時能夠從新配置使用新master的slave的數量。數字越低,更多的時間將會用故障轉移完成,可是若是slaves配置爲服務舊數據,你可能不但願全部的slave同時從新同步master。由於主從複製對於slave是非阻塞的,當中止從master加載批量數據時有一個片刻延遲。經過設置選項爲1,確信每次只有一個slave是不可到達的。

其餘的選項在本文檔其餘部分有描述,而且在示例sentinel.conf的備有文件裏有附帶說明。 

全部的Sentinel參數在運行時可使用SENTINEL SET命令更改。查看在運行時從新配置Sentinel部分了解更多。 

Sentinel部署示例 

既然你知道了sentinel的基本信息,你能夠很想知道應該將Sentinel放置在哪裏,須要多少Sentinel進程等等。這個章節展現了幾個部署示例。 

咱們爲了圖像化展現配置示例使用字符藝術,這是不一樣符號的意思: 

+--------------------+
| This is a computer |
| or VM that fails   |
| independently. We  |
| call it a "box"    |
+--------------------+

咱們寫在盒子裏表示他們正在運行什麼: 

+-------------------+
| Redis master M1   |
| Redis Sentinel S1 |
+-------------------+

不一樣的盒子之間經過線條鏈接,表示他們能夠相互通訊: 

+-------------+               +-------------+
| Sentinel S1 |---------------| Sentinel S2 |
+-------------+               +-------------+

使用斜槓展現網絡斷開: 

+-------------+                +-------------+
| Sentinel S1 |------ // ------| Sentinel S2 |
+-------------+                +-------------+

還要注意: 

  • Master 被叫作 M1,M2,M3 ... Mn。
  • Slave 被叫作 R1,R2,R3 ... Rn(replica的首字母)
  • Sentinels 被叫作 S1,S2,S3 ... Sn
  • Clients 被叫作 C1,C2,C3 ... Cn
  • 當一個實例由於Sentinel的行爲改變了角色,咱們把它放在方括號裏,因此[M1]表示由於Sentinel的介入,M1如今是一個master。

注意永遠不會顯示的設置只是使用了兩個哨兵,由於爲了啓動故障轉移,Sentinel老是須要和其餘大多數的Sentinel通訊。 

實例1,只有兩個Sentinel,不要這樣作 

+----+         +----+
| M1 |---------| R1 |
| S1 |         | S2 |
+----+         +----+

Configuration: quorum = 1
  • 在這個設置中,若是master M1故障,R1將被晉升由於兩個Sentinel能夠達成協議而且還能夠受權一個故障轉移由於多數就是兩個。因此他表面上看起來是能夠工做的,然而檢查下一個點了解爲何這個設置是不行的。
  • 若是運行M1的盒子中止工做了,S1也中止工做。運行在其餘盒子上的S2將不能受權故障轉移,因此係統將變成不可用。

注意爲了排列不一樣的故障轉移須要少數服從多數,而且稍後向全部的Sentinel傳播最新的配置。還要注意上面配置的故障轉移的能力,沒有任何協定,很是危險: 

+----+           +------+
| M1 |----//-----| [M1] |
| S1 |           | S2   |
+----+           +------+

在上面的配置中咱們使用完美的對稱方式建立了兩個master(假定S2能夠在未受權的狀況下進行故障轉移)。客戶端可能會不肯定往哪邊寫,而且沒有途徑知道何時分區配置是正確的,爲了預防一個永久的斷裂狀態。 

全部請永遠部署至少三個Sentinel在三個不一樣的盒子裏。 

例2:使用三個盒子的基本設置 

這是個很是簡單的設置,它有簡單調整安全的優點。它基於三個盒子,每一個盒子同時運行一個Redis實例和一個Sentinel實例。 

+----+
       | M1 |
       | S1 |
       +----+
          |
+----+    |    +----+
| R2 |----+----| R3 |
| S2 |         | S3 |
+----+         +----+

Configuration: quorum = 2

若是M1故障,S2和S3將會商定故障並受權故障轉移,使客戶端能夠繼續。 

在每一個Sentinel設置裏,Redis是異步主從複製,總會有丟失數據的風險,由於有可能當它成爲master的時候,一個確認的寫入操做尚未同步到slave。而後在上面的設置中有一個更高的風險因爲客戶端分區一直是老的master,就像下面的圖像所示: 

 

+----+
         | M1 |
         | S1 | [- C1 (writes will be lost)
         +----+
            |
            /
            /
+------+    |    +----+
| [M2] |----+----| R3 |
| S2   |         | S3 |
+------+         +----+

 

在這個案例中網絡分區隔離老的master M1,因此slave R2晉升爲master。然而客戶端,好比C1,還在原來的老的master的分區,可能繼續往老master寫數據。這個數據將會永久丟失,由於分區恢復時,master將會從新配置爲新master的slave,丟棄它的數據集。 

這個問題可使用下面的Redis主從複製特性減輕,它可在master檢查到它再也不能傳輸它的寫入操做到指定數量的slave的時候中止接收寫入操做。 

min-slaves-to-write 1
min-slaves-max-lag 10

使用上面的配置(請查看自帶的redis.conf示例瞭解更多信息)一個Redis實例,看成爲一個master,若是它不能寫入至少1個slave將中止接收寫入操做。(N個Slave以上不通就中止接收) 

因爲主從複製是異步的不能真實的寫入,意味着slave斷開鏈接,或者再也不向咱們發送異步確認的指定的max-lag秒數。(斷定鏈接不通的超時時間) 

在上面的示例中使用這個配置,老master M1將會在10秒鐘後變爲不可用。當分區恢復時,Sentinel配置將指向新的一個,客戶端C1將可以獲取到有效的配置而且將使用新master繼續工做。 

然而天下沒有免費的午飯,這種改進,若是兩個slave掛掉,master將會中止接收寫入操做。這是個權衡。 

例三:Sentinel在客戶端盒子裏 

有時咱們只有兩個Redis盒子可用,一個master和一個slave。在例二中的配置在那樣的狀況下是不可行的,所謂咱們能夠藉助下面的,Sentinel放置在客戶端: 

 

+----+         +----+
            | M1 |----+----| R1 |
            | S1 |    |    | S2 |
            +----+    |    +----+
                      |
         +------------+------------+
         |            |            |
         |            |            |
      +----+        +----+      +----+
      | C1 |        | C2 |      | C3 |
      | S1 |        | S2 |      | S3 |
      +----+        +----+      +----+

      Configuration: quorum = 2

在這個設置裏,Sentinel的視角和客戶端的視角相同:若是大多數的客戶端認爲master是能夠到達的,它就是好的。C1,C2,C3是通常的客戶端,這不意味着C1識別單獨的客戶端鏈接到Redis。它更像一些如應用服務,Rails應用之類的。 

若是運行M1和S1的盒子故障,故障轉移將會發生,然而很容看到不一樣的網絡分區將致使不一樣的行爲。例如若是客戶端和Redis服務之間的斷開鏈接,Sentinel將不能設置,由於master和slave將都不可用。 

注意若是使用M1獲取分區,咱們有一個和例二中描述的類似的問題,不一樣的是這裏咱們沒有辦法打破對稱,因爲只有一個slave和master,因此當它的master斷開鏈接時master不能中止接收查詢,不然在slave故障期間master將永不可用。 

因此這是個有效的設置可是在例二中的設置有像更容易管理HA系統的優勢, 並有能力限制master接收寫入的時間。 

例4:少於3個客戶端的Sentinel客戶端 

在例3中若是客戶端少於3個就不能使用。在這個案例中咱們使用一個混合的設置: 

+----+         +----+
            | M1 |----+----| R1 |
            | S1 |    |    | S2 |
            +----+    |    +----+
                      |
               +------+-----+
               |            |  
               |            |
            +----+        +----+
            | C1 |        | C2 |
            | S3 |        | S4 |
            +----+        +----+

      Configuration: quorum = 3

這裏和例3很是相似,可是這裏咱們在4個盒子裏運行四個哨兵。若是M1故障其餘的三個哨兵能夠執行故障轉移。 

Sentinel,Docker,NAT,和可能的問題 

Docker使用一個叫端口映射的技術:程序運行在Docker容器能夠暴露一個不一樣端口。這很是有助於在相同的服務器上相同的時間使用相同的端口運行多個容器。 

Docker不只僅能夠實現這個功能,還有其餘的設置能夠從新映射端口,有時是端口,有時是IP地址。 

從新映射端口和地址有兩個問題: 

  1. Sentinel自動發現其餘再也不工做的Sentinel,由於它基於每一個Sentinel監聽鏈接的端口和IP的問候消息。然而不知道地址和端口是從新映射的,因此它會宣告不正確的配置信息。
  2. Slaves以相同的方式列在master的Info輸出裏:經過master檢測每一個TCP鏈接檢測地址,由於端口是經過slave本身在握手期間廣告的,然而端口就像第一點裏說的是錯誤的。

快速教程 

本文接下來的章節裏,將逐步覆蓋關於Sentinel API,配置,和語義的全部細節。然而對於那些想盡快使用系統的人,這個章節是一個教程,展現怎麼使用三個Sentinel實例配置。 

這裏咱們假定實例已經運行在5000,5001,5002。還假定Redis master運行在6379端口,slave運行在6380端口。在這個教程裏咱們使用IPv4迴路地址127.0.0.1,假定運行在你的我的電腦裏。 

三個Sentinel配置文件應該是這樣的: 

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

另外的兩個配置文件除了使用5001和5002端口外,其餘所有相同。 

上面的配置中須要注意一些事情: 

  • master 叫作 mymaster。它標識master和它的slave。由於每一個master設置有個不一樣的名字,Sentinel能夠同時監控不一樣組的master和slave。
  • quorum設置爲2(sentinel monitor指令的最後一個參數)。
  • down-after-milliseconds 的值爲5000毫秒,也就是5秒,因此一旦咱們在這個時間範圍內不能接收響應,master將會被標記爲故障。

一旦你啓動三個Sentinel,你將會看到一些消息日誌,像: 

+monitor master mymaster 127.0.0.1 6379 quorum 2

這是Sentinel事件,若是你SUBSCRIBE事件名稱,你能夠經過Pub/Sub接收到各類事件。 

Sentinel在故障檢測和轉移期間生產並記錄不一樣的事件。 

訪問Sentinel master的狀態 

開始使用Sentinel最明顯的事情是,檢查master是否正常監控: 

$ redis-cli -p 5000
127.0.0.1:5000] sentinel master mymaster
 1) "name"
 2) "mymaster"
 3) "ip"
 4) "127.0.0.1"
 5) "port"
 6) "6379"
 7) "runid"
 8) "953ae6a589449c13ddefaee3538d356d287f509b"
 9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "735"
19) "last-ping-reply"
20) "735"
21) "down-after-milliseconds"
22) "5000"
23) "info-refresh"
24) "126"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "532439"
29) "config-epoch"
30) "1"
31) "num-slaves"
32) "1"
33) "num-other-sentinels"
34) "2"
35) "quorum"
36) "2"
37) "failover-timeout"
38) "60000"
39) "parallel-syncs"
40) "1"

就像你看到的,它打印了大量的關於master的信息。有一些是對於咱們很是有用的: 

  • num-other-sentinels 是2,因此咱們知道Sentinel已經檢測到這個master的其餘兩個Sentinel。若是你檢查日誌,你會看到生成了 +sentinel 事件。
  • flags 是 master。若是master down了,咱們在這裏但願看到 s_down 或者 o_down。
  • num-slaves這裏是1,因此Sentinel還檢測到master有一個slave。

爲了更多的探索這個實例,你可能想嘗試下面的兩個命令: 

SENTINEL slaves mymaster
SENTINEL sentinels mymaster

第一個會打印鏈接到master的slave的信息,第二個是關於其餘Sentinel的信息。 

獲取當前master地址 

咱們已經說明,Sentinel還能夠做爲客戶端的配置提供者,鏈接到一組master和slave。由於故障轉移和從新配置,客戶端沒有辦法指定誰是當前活動master,因此Sentinel提供了一個API解決這個問題: 

127.0.0.1:5000] SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6379"

測試故障轉移 

這時候咱們部署的sentinel已經準備好了測試。咱們只須要kill掉master檢查配置是否改變。因此只須要作以下的事情: 

redis-cli -p 6379 DEBUG sleep 30

這個命令將使master休眠30秒不能訪問。這主要是模仿master因爲一些緣由掛掉。 

若是你檢查Sentinel日誌,以應該能看到不少動做: 

  • 每一個Sentinel檢查到master掛掉,有一個+sdown事件。
  • 這個時間稍後升級到 +odown,這意味着多個Sentinel商定了master不可到達的事實。
  • Sentinels投票選舉一個Sentinel啓動第一次故障轉移。
  • 發生故障轉移。

若是你再次訪問 mymaster 當前master的地址,最終你此次應該獲得一個不同的答案: 

127.0.0.1:5000] SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6380"

到目前位置一切都順利,這個時候你能夠跳轉到建立Sentinel部署或者能夠閱讀更多信息瞭解全部的Sentinel命令和內部構建。 

Sentinel API 

Sentinel 提供了一個AP以便於檢查它的狀態,檢查監控的master和slave的健康,訂閱接收特定的通知,和在運行時改變Sentinel配置。 

Sentinel默認使用TCP端口26379(注意6379是標準的Redis端口)。Sentinels使用Redis協議接收命令,因此你可使用 redis-cli 或任何其餘的Redis客戶端和Sentinel通訊。 

能夠直接查詢Sentinel檢查監控的Redis實例的狀態,查看它知道的其它Sentinel,等等。或者,使用Pub/Sub,能夠從Sentinel接收推送類型的通知,每次有事件發生,例如故障轉移,或者實例進入錯誤條件,等等。 

Sentinel 命令 

下面是一系列的接收命令,而不是所有的命令,用於修改Sentinel配置。 

  • PING - 這個命令簡單的返回PONE。
  • SENTINEL masters - 展現監控的master清單和它們的狀態。
  • SENTINEL master [master name] - 展現指定master的狀態和信息。
  • SENTINEL slaves [master name] - 展現master的slave清單和它們的狀態。
  • SENTINEL sentinels [master name] - 展現master的sentinel實例的清單和它們的狀態。
  • SENTINEL get-master-addr-by-name [master name] - 返回master的IP和端口。若是故障轉移在處理中或成功終止,返回晉升的slave的IP和端口。
  • SENTINEL reset [pattern] - 這個命令將重置全部匹配名字的masters。參數是blog風格的。重置的過程清空master的全部狀態,並移除已經發現和關聯master的全部slave和sentinel。
  • SENTINEL failover [master name] - 若是master不可到達,強制執行一個故障轉移,而不徵求其餘Sentinel的贊成。
  • SENTINEL ckquorum [master name] - 檢查當前的Sentinel配置是否可以到達故障轉移須要的法定人數,而且須要受權故障轉移的多數。這個命令應該用於監控系統檢查部署是否正確。
  • SENTINEL flushconfig - 強制Sentinel在磁盤上重寫它的配置,包括當前的Sentinel狀態。一般Sentinel每次重寫配置改變它的狀態。然而有時因爲操做錯誤、硬盤故障、包升級腳本或配置管理器可能致使配置文件丟失。在這種狀況下收到強制Sentinel重寫配置文件。這個命令即便上面的配置文件徹底不見了。

運行時配置Sentinel 

從Redis 2.8.4開始,Sentinel提供了API以便於添加、刪除、或者修改指定master的配置。注意若是有多個Sentinel,應該申請更改全部的Redis Sentinel實例。這意味這修改一臺Sentinel不會在網絡上自動傳播到其餘的Sentinel實例。 

下面是SENTINEL的子命令清單,用於修改Sentinel實例的配置。 

  • SENTINEL MONITOR  [name] [ip] [port] [quorum] - 這個命令告訴Sentinal開始使用指定的name、ip、port、quorum監控新master。這個sentinel.conf配置文件裏的指令徹底相同,區別是這裏不能使用主機名做爲IP,你須要提供一個IPv4或IPv6地址。
  • SENTINEL REMOVE  [name] - 用於刪除指定的master:master將再也不受監控,並從Sentinel內部狀態徹底刪除,因此經過SENTINEL masters命令不會再列處理,等等。
  • SENTINEL SET [name] [option] [value] - SET命令和Redis的CONFIG SET 很是類似,用於修改指定master的配置參數。能夠指定多組option / value。全部經過sentinel.conf配置的參數均可以經過SET命令設置。

下面是一個SENTINEL SET 命令的例子,用於修更名叫objects-cache的master的down-after-milliseconds。 

SENTINEL SET objects-cache-master down-after-milliseconds 1000

正如前面提到的,SENTINEL SET 能夠用於配置全部可在啓動配置文件裏設置的參數。此外還能夠值更改quorum配置而不用刪除和從新添加master,只是使用: 

SENTINEL SET objects-cache-master quorum 5

注意沒有對應的GET命令由於SENTINEL MASTER以簡單的格式提供了全部的配置參數。 

添加或刪除Sentinel 

添加新的Sentinel很是簡單由於Sentinel實現了自動檢測的機制。你須要作的就是啓動新的Sentinel配置監控當前活動的master。10秒以內Sentinel就會得到其餘的Sentinel列表和master的slave。 

若是你須要一次添加多個Sentinel,建議添加一個以後再添加另外一個,在添加下一個以前等待其餘的Sentinel已經知道了第一個Sentinel。這有助於始終保證能夠在一個分區得到多數,在添加Sentinel過程當中發生故障的機會。 

經過每添加一個Sentinel有一個30秒的延遲很是容易得到。 

在這個過程的最後要使用命令SENTINEL MASTER mastername一邊檢查是否全部Sentinel贊成監控master的Sentinel的總數。 

刪除Sentinel有點複雜:Sentinel永遠不會忘記見到過的Sentinel,即便它們在很長時間內不能到達,由於咱們不但願動態的改變須要受權的多數並建立一個新值。因此爲了刪除一個Sentinel應該在網絡分區裏執行如下步驟: 

  1. 中止想要刪除的Sentinel進程。
  2. 發送一個SENTINEL RESET * 命令到全部的Sentinel實例。在執行實例之間每一個至少等待30秒鐘。
  3. 檢查全部Sentinel協商的當前活動的Sentinel數量,經過檢查每一個Sentinel的SENTINEL MASTER mastername輸出。

刪除老master或不可及的slave 

Sentinels從不會忘記指定master的slave,即便他們有很長時間不可及。這很是有用,由於Sentinels應該可以正確的從新配置網絡分區或故障事件以後返回的slave。 

此外,故障轉移以後,轉移故障的master實質上添加做爲新master的slave,這個方式一旦它再次可用就會從新配置重新master複製。 

然而有時候你可能想從哨兵監控的slave列表裏永久的刪除一個salve(也多是老master)。 

爲了作到這個事情,你須要向全部的哨兵發送一個SENTINEL RESET mastername命令:他們將會在10秒內刷新slave列表,只添加一個列表複製當前master的信息輸出。 

發佈/訂閱消息 

客戶端可使用Sentinel做爲Redis兼容的發佈/訂閱服務器以便於SUBSCRIBE或PSUBSCRIBE通道並得到關於特殊事件的通知。 

通道的名字和事件的名字相同。好比通道的名字是 +sdown 將會接收全部實例進入 SDOWN 狀態的通知。(SDWON意思是實例從Sentinel的視角再也不可及) 

訂閱全部的消息只須要使用 PSUBSCRIBE *。 

下面是你可使用的API通道和消息格式列表。第一個單詞是通道/事件名稱,其他的部分是數據格式。 

注意:指定的 instance details部分意思是提供下面的參數肯定目標實例。 

[instance-type] [name] [ip] [port] @ [master-name] [master-ip] [master-port]

表示master的部分(從@到最後)是可選的並只在實例不是master本身的時候指定。 

  • +reset-master [instance details] -- master被重置。
  • +slave [instance details] -- 發現附加一個新slave。
  • +failover-state-reconf-slave [instance  details] -- 故障轉移狀態更改成 reconf-slaves 狀態。
  • +failover-detected [instance details] -- 有另外一個Sentinel啓動一個故障轉移或者任何其餘的外部實體被檢測到(附加的salve變成master)。
  • +slave-reconf-sent [instance details] -- leader sentinel向實體發送 SALVEOF命令以便於從新配置新Slave。
  • +slave-reconf-inprog [instance details] -- slave正在被重新配置爲新master的slave,可是同步過程尚未完成。
  • +slave-reconf-done [instance details] -- slave如今已經同步到新master。
  • -dup-sentinel [instance details] -- 指定master的一個或多個Sentinel被移除。(當Sentinel實例重啓時會發生)
  • +sentinel [instance details] -- 發現添加一個sentinel。
  • +sdown [instance details] -- 指定的實例如今在主觀上是Down狀態。
  • -sdown [instance details] -- 指定的實例再也不是主觀上的Down狀態。
  • +odown [instance details] -- 指定的實例如今在客觀上是Down狀態。
  • -odown [instance details] -- 指定的實例在客觀上再也不是Down狀態。
  • +new-epoch [instance details] -- 當前時代被更新。
  • +try-failover [instance details] -- 新故障轉移過程當中,等待其餘多數決定。
  • +elected-leader [instance details] -- 指定的時代贏得了選舉,能夠執行故障轉移。
  • +failover-state-select-slave [instance details] -- 新的故障轉移狀態是 select-slave:嘗試查找適當晉升的slave。
  • no-good-slave [instance details] -- 沒有適當晉升的slave。稍後重試,可是這可能會發生改變並終止故障轉移。
  • selected-slave [instance details] -- 找到適合晉升的slave。
  • failover-state-send-slaveof-noone [instance details] -- 嘗試從新配置晉升的slave做爲master,等待轉換。
  • failover-end-for-timeout [instance details] -- 因爲超時終止故障轉移,無論怎樣,slave最後將被配置爲複製新master。
  • failover-end [instance details] -- 故障轉移成功完成。全部slaves被從新配置爲新master的從。
  • switch-master [master name] [oldip] [oldport] [newip] [newport] -- 在改變配置以後指定master新IP和地址。這是大多數外部用戶感興趣的消息。
  • +tilt -- 進入 Tilt模式。
  • -tilt -- 退出 Tilt模式

處理 -BUSY狀態 

當Lua腳本運行時間超過配置的Lua腳本時間限制時,Redis實例返回-BUSY錯誤。在觸發故障轉移以前發生這種狀況時,Sentinel將嘗試發送一個 SCRIPT KILL命令,它只在腳本只讀的時候成功。 

若是嘗試過這個以後實例還是一個錯誤狀態,最後就會啓動故障轉移。 

Slaves優先級 

Redis實例有一個salve-priority的配置參數。這個信息暴露在Redis slave的 INFO 輸出裏,Sentinel使用它以便於在可用的salves中獲取slave進行故障轉移: 

  • 若是Slave優先級設置爲0.slave永遠不會晉升爲master。
  • 優先級數字越低越被Sentinel優先選擇。

例如若是有一個slave S1在當前master的同一個數據中心,而且另外一個salve S2在另外一個數據中心,能夠設置S1的優先級爲10,S2的優先級爲100,因此若是master故障而且S1和S2均可用,S1將會被優先選擇。 

瞭解關於slave選擇的更多信息,請參考 本文檔的 slave選擇和優先級部分。 

Sentinel和Redis身份驗證 

當master配置要求從客戶端提供密碼做爲安全措施時,slave也須要知道這個密碼以便於master的身份驗證並創建master-slave之間的鏈接用於異步複製協議。 

經過如下配置指令能夠實現: 

  • requirepass 在master裏,設置身份驗證密碼,並肯定實例不處理沒有身份驗證的客戶端請求。
  • masterauth 在slave裏,爲了slave驗證master以便於從master正確的複製數據。

當使用Sentinel時,沒有單獨的master,由於在故障轉移以後slave能夠改變master的角色,而且老master能夠被從新配置爲slave,因此你要作的是在master和slaves的全部實例裏都配置上上面的指令。 

這一般也是一個理智的設置由於你不僅是想保護master裏的數據,在slave裏也是同樣。 

然而在一些罕見的狀況下你須要slave不進行身份驗證就能夠訪問,你能夠將slave的優先級設置爲0,放置這個slave升級爲master,並在這個slave裏只配置masterauth指令,不用requirepass指令,以便於沒有受權的客戶端也能夠訪問。 

Sentinel客戶端實現 

Sentinel須要顯示的客戶端支持,除非系統被配置爲執行腳本對全部請求執行重定向到新master實例。客戶端類庫的實現話題在文檔Sentinel clients guidelines有覆蓋。 

更多高級概念 

接下來的部分咱們將會涉及Sentinel怎麼工做的一些細節,沒有依靠實現細節和算法並會在本文檔的其餘部分涉及。 

SDOWN和ODOWN故障狀態 

Redis Sentinel對於正在down的狀態有兩個不一樣的概念,一個叫作主管的DOWN(SDOWN),它是一個本地Sentinel實例的狀態。另外一個叫客戶端的Down(ODOWN),當足夠的Sentinel SDOWN狀態是可達的,而且從其餘的Sentinel使用SENTINEL is-master-down-by-addr命令獲得反饋,就進入ODOWN狀態。 

從Sentinel的視角,當它在配置文件is-master-down-after-milliseconds參數指定的時間以內沒有收到有效的PING響應就會進入一個SDOWN條件。 

PING的響應是下面的其中之一: 

  • PONE
  • -LOADING 錯誤
  • -MASTERDOWN 錯誤

任何其餘的響應都視爲無效。可是注意一個合理的master通知本身在INFO輸出裏做爲salve被視爲down。 

注意SDOWN要求不可接受的請求是對整個配置間隔,因此例如若是間隔是30000毫秒,且咱們每29秒接受的一個ping請求,實例被認爲是正常運行的。 

SDOWN不能觸發故障轉移:這只是意味着一個單獨Sentinel認爲Redis實例不可及。觸發一個故障轉移,必須到達ODWN狀態。 

從SDOWN轉換到ODOWN沒有共識的算法,僅僅是形式上的:若是一個指定的Sentinel從足夠多的Sentinel得到報告在指定的時間範圍內master沒有工做,SDOWN就升級爲ODOWN。若是確認在稍後丟失,標記就被清空。 

更嚴格的身份驗證是須要大多數確認以便於真正的啓動故障轉移,可是沒有到ODOWN狀態不會觸發故障轉移。 

ODOWN只適用於master。其餘的實例Sentinel不要求,因此SLAVE和其餘sentinel永遠不會到達ODOWN狀態,僅僅是SDOWN。 

SDOWN還有其餘含義。例如Sentinel執行故障轉移時slave在SDOWN狀態不會被選中晉級。 

自動發現Sentinels和Slaves 

Sentinel保持與其餘Sentinel的鏈接以便於相互的檢查可用性,並傳輸消息。然而你不須要在每一個Sentinel實例裏配置其餘Sentinel的地址,由於Sentinel使用Redis實例的發佈/訂閱功能用於發現監控相同master和slave的其餘Sentinel。 

這個功能由向_sentinel_:hello通道發送問候消息實現。 

一樣你不須要配置master附加的slave列表,由於Sentinel會自動發現。 

  • Sentinel每兩秒發佈一個消息到每一個監控的master和slave 發佈/訂閱通道_sentinel_hello,消息內容包括ip,port,runid宣佈他的存在。
  • Sentinel訂閱每一個master和slave的_sentinel_:hello通道,查找不知道的sentinels。一旦檢測到新的sentinel,他們就添加爲這個master的sentinel。
  • 問候消息包括當前master完整的配置。若是Sentinel有一個配置比接收的老,它會馬上更新配置。
  • 在添加sentinel到master以前,sentinel老是檢測是否已經有相同runid或相同地址的sentinel。在這種狀況下會刪除全部匹配的sentinel,並添加新的。

故障轉移過程以外的從新配置 

即便不進行故障轉移,Sentinel也會一直嘗試設置當前配置。特別的: 

  • Slaves成爲master,將會配置爲當前master的slave。
  • Slave鏈接到錯誤的master,會從新配置爲正確的master。

Sentinels從新配置slaves,有時必須監控錯誤配置,比周期性的廣播新配置要好。 

Sentinel使用狀態配置信息在接收更新以前嘗試改變slaves配置。 

還要注意怎樣嘗試利用當前配置防止故障分區: 

  • Master在可用的時候被從新配置爲slave。
  • Slaves分區在從新配置分區期間一旦可及就會被從新配置。

在這個部分要記住的重要的是:Sentinel是一個系統,每一個進程一直嘗試利用最後一個合理的配置設置監控的實例。 

Slave選擇和優先級 

當Sentinel實例準備執行故障轉移時,因爲master在ODOWN狀態且從多數的Sentinel實例接收到受權,須要選擇一個適當的slave。 

選擇過程會評估slave下面的信息: 

  1. 從master斷開的次數。
  2. Slave優先級。
  3. 複製偏移量。
  4. Run ID。

發現Slave從master斷開超過10倍的超時時間,加上Sentinel認爲master不可用的時間,就認爲不適合故障轉移並跳過。 

更嚴格的條件,slave的INFO輸出信息顯示從master斷開超過: 

(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

被認爲是不適合的並徹底忽略。 

Slave選擇只認爲經過上面的測試,並在上面的標準基礎上排序: 

  1. Slave經過Redis實例的redis.conf文件配置的slave-priority排序。優先級越低越被優先考慮。
  2. 若是優先級相同,檢查slave的複製偏移量,並選擇接收更多數據的slave。
  3. 若是多個slave有相同的優先級和一樣的處理數據過程,就會執行一個更進一步的驗證,選擇一個有較短run ID的slave。run ID 對於 slave沒太大用,可是很是有助於選擇slave的過程,而不是隨機選擇slave。

若是要強烈的匹配,Redis master和slaves都要配置 salve-priority。不然全部的實例可使用默認的run ID運行(建議這樣設置,由於這比經過複製偏移量選擇slave更感興趣)。 

Redis實例能夠配置特定的slave-priority爲0用於永遠不讓sentinel選舉爲master。可是用這種方式配置slave會在故障轉移以後從新配置以便於複製新master的數據,不一樣的只是他永遠不會變成一個master。 

算法和內部構建 

在接下來的部分咱們將會探究Sentinel特性的細節。用戶不須要關注全部的細節,可是深度理解能夠幫你更有效的開發和操做Sentinel。 

Quorum 

上面的章節中展現了每一個監控的master都關聯一個quorum配置。它指定須要商定master不可及或錯誤條件Sentinel進程數量以便於觸發故障轉移。 

然而,觸發故障轉移以後,爲了真正的執行故障轉移,至少大多數的Sentinel必須受權Sentinel進行故障轉移。若是隻有少數的Sentinel存在,Sentinel將永遠不會執行故障轉移。 

讓咱們試着使事情更清晰: 

  • Quorum:須要檢測錯誤條件以便於標記master爲ODOWN的Sentinel進程數量。
  • 經過ODOWN狀態觸發故障轉移。
  • 一旦觸發了故障轉移,Sentinel嘗試請求大多數的Sentinel受權故障轉移(若是quorun設置的數量大於多數,則須要大於等於)。

不一樣之處彷佛很小,可是很容易理解和使用。例如若是你有5個Sentinel實例,quorum設置爲2,一旦2個Sentinel認爲master不可及就會觸發故障轉移,可是隻有其中一個Sentinel獲得至少3個贊成的時候才能夠故障轉移。 

若是把quorum配置爲5,全部的Sentinel都必須統一master的錯誤條件,且從全部的Sentinel獲得受權才能夠故障轉移。 

這意味着quorum能夠經過兩個方式用於調整Sentinel: 

  1. 若是quorum設置的值小於咱們部署的大多數Sentinel,這基本上是合理的,即便少數的Sentinel不可通訊業能夠觸發故障轉移。
  2. 若是quorum設置的值大於多數的Sentinels,只有當大多數的Sentinel鏈接正常並贊成才能夠故障轉移。

配置 epochs 

Sentinel要求從多數得到受權以便於啓動故障轉移有幾個重要緣由: 

當一個Sentinel被受權,它獲得一個惟一的配置epoch控制故障轉移。這是一個數字它將用於在故障轉移以後新配置的版本。由於多數贊成受權指定的版本到指定的Sentinel,沒有其餘的Sentinel可以使用它。這意味着每一個故障轉移的配置都有一個惟一的版本。咱們就知道了這爲何這麼重要。 

此外Sentinel有個規則:若是Sentinel選舉其餘的Sentinel啓動指定master的故障轉移,它將等待一些時間再次嘗試相同的master。這個延遲時間你能夠在sentinel.conf文件裏配置failover-time。 

這意味着Sentinel在相同的時間不會嘗試相同的master,先嚐試第一個受權,若是失敗在段時間後嘗試另外一個,以此類推。 

Redis Sentinel保證liveness屬性若是多數Sentinels能夠通訊,最後就會被受權故障轉移若是master是down。 

Redis Sentinel還保證safety屬性每一個Sentinel將使用不一樣的configuration epoch轉移相同的master。 

配置傳播 

一旦Sentinel可以成功的故障轉移master,它將啓動傳播新的配置以便於其餘的Sentinel更新指定master的信息。 

一個故障轉移被認爲是成功的,它須要Sentinel可以發送SLAVEOF NO ONE命令到選擇的slave,而且切換到master稍後會在master的INFO輸出裏觀察。 

這時候,即便在slave的從新配置過程當中,故障轉移也被認爲是成功的,且全部的Sentinel被要求報告新配置。 

新配置方式的傳播方式就是爲何咱們須要用不一樣的版本號(epoch)受權每一個Sentiel故障轉移的緣由。 

每一個Sentinel使用發佈/訂閱消息的方式接二連三的傳播它的配置版本,在相同的時間全部的Sentinel等待消息查看其餘Sentinel傳播的配置是什麼。 

配置信息在_sentinel_:hello發佈/訂閱通道里廣播。 

由於每一個配置有不一樣的版本號,高版本老是賽過低版本。 

因此好比全部的Sentinel認爲master在192.168.1.53:6379。這個配置的版本是1.一些時間以後被受權的故障轉移版本是2.若是故障轉移成功,它會開始廣播新配置,好比192.168.1.50:9000.全部的其餘實例會看到這個版本號是2的配置並更新他們的配置,由於新的配置有更高的版本號。 

這意味着Sentinel保證一個第二leveness屬性:一組Sentinel可以通訊並聚集更高保本號更新相同的配置。 

基本上若是網絡分區,每一個分區將聚集更高的本地配置。在特殊的案例中沒有分區,有一個單獨的分區且每一個Sentinel會商定配置。 

分區下的一致性 

Redis Sentinel配置最終是一致的,因此配個分區將聚集更高可用的配置。然而在現實系統中使用Sentinel有三個不一樣的角色: 

  1. Redis Instances。
  2. Sentinel instances。
  3. Clients。

爲了定義系統特性咱們必須考慮這三個角色。 

下面是一個簡單的有三個節點的網絡,每一個節點運行一個Redis實例和一個Sentinel實例: 

+-------------+
            | Sentinel 1  |----- Client A
            | Redis 1 (M) |
            +-------------+
                    |
                    |
+-------------+     |          +------------+
| Sentinel 2  |-----+-- // ----| Sentinel 3 |----- Client B
| Redis 2 (S) |                | Redis 3 (M)|
+-------------+                +------------+

這個系統中初始狀態是Redis3是master,Redis1和2是slaves。發生了一個分區隔離了老master,Sentnel1和2啓動一個故障轉移將Sentinel 1升級爲master。 

Sentinel屬性保證Sentinel1和2如今有master的新配置。然而3始終是老配置由於它在不一樣的分區裏。 

咱們知道當網絡分區修復以後Sentinel3會獲取更新的配置,然而在分區期間若是有客戶端鏈接老master分區會發生什麼? 

客戶端會始終能寫到Redis 3,老的master。當分區從新接入,Redis 3將從新變爲Redis 1的salve,而且全部在分區期間寫入的數據都將會丟失。 

根據你的配置你可能不想讓這個事情發生: 

  1. 若是你正在使用Redis做爲緩存,它可使客戶端B可以寫入到老master,即便數據丟失。
  2. 若是你正在做爲存儲,這就很差了並且你須要配置系統以便於部分的防止這個問題。

由於Redis是異步複製,沒有辦法徹底的防止數據丟失,然而你可使用下面的配置選項綁定Redis3和Redis1之間的鬆散度。 

min-slaves-to-write 1
min-slaves-max-lag 10

 

使用上面的配置,當切換master時,若是有1臺以上slave不可寫入就會中止接收寫入操做。 

由於主從複製是異步的,slave斷開鏈接或者不發送異步確認大於指定的max-lag的秒數意味着不能真正的寫入。 

在上面的例子中使用這個配置,Redis3會在10秒以後變爲不可用。當分區恢復時,Sentinel 3配置將聚集新的,且Client B可以檢查有效的配置並繼續。 

一般Redis+Sentinel做爲一個總體是一個最終一致的系統,且數據丟棄老的複製當前master的數據,因此始終有一個丟失確認寫入的窗口。這是由於Redis異步複製。注意這是Sentinel自身的限制,若是你想完整一致的故障轉移,相同的屬性將仍然適用。有兩個方法避免丟失確認的寫入: 

  • 使用同步複製
  • 使用一致性系統。

Redis如今不能使用上面的任何系統,而且這在開發目標以外。可是有代理實現的方案2,例如SoundCoud Roshi,或者 Netfix Dynomite。 

Sentinel持久化狀態 

Sentinel狀態持久化到Sentinel配置文件裏。例如每次接收一個新配置,或者建立,配置文件會和配置epoch一塊兒持久化到硬盤上。 

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

TILT 模式 

Redis Sentinel嚴重依賴於計算機時間:例如爲了理解一個實例是否可用,它記錄上次成功響應PING命令的時間,並和當前時間對比分析已經多久了。 

然而若是計算機時間意外的改變了,或者計算機很是忙,或者進程因爲某些緣由損壞,Sentinel可能會有一個意想不到的行爲。 

TILT模式是一個特殊的 "protection" 模式,當檢測到能夠下降系統可靠性怪異現象時,Sentinel能夠進入 "protection" 模式。Sentinel時間計數器通常每秒調用10次,因此咱們指望大約100毫秒在兩個調用之間中斷。 

什麼哨兵調用中判定時器,並和當前調用對比:若是時常是負數或出乎意料的大(2秒或更大)就進入TILT模式。 

當進入TILT模式,Sentinel將繼續監控每件事,除了: 

  • 中止代理。
  • 開始否認的回答SENTINEL is-master-down-by-addr請求,再也不可信。

一切恢復正常30秒以後,就退出TILT模式。 

注意在某些方面TILT模式可使用不少內核支持的單調時鐘API替換。然而仍不清楚這是不是一個好的解決方案,由於當前系統避免問題的過程只是在很長時間暫停或不執行調度。

相關文章
相關標籤/搜索