轉載自Redis中文網 - Redis哨兵-實現Redis高可用html
Redis哨兵爲Redis提供了高可用性。實際上這意味着你可使用哨兵模式建立一個能夠不用人爲干預而應對各類故障的Redis部署。redis
哨兵模式還提供了其餘的附加功能,如監控,通知,爲客戶端提供配置。 算法
下面是在宏觀層面上哨兵模式的功能列表: 緩存
Redis哨兵是一個分佈式系統: 安全
哨兵自身被設計成和多個哨兵進程一塊兒合做運行。有多個哨兵進程合做的好處有: 服務器
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地址的鏈接。不然哨兵不能通訊和商定作什麼,故障轉移將永不會執行。
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須要解釋一下:
例如你有5個哨兵進程,而且給定的master的quorum的值設置爲2,這是將發生的事情:
實際上這意味着在故障轉移期間若是大多數的Sentinel進程不能通訊,Sentinel將會永不啓動故障轉移(即在少數分區沒有故障轉移)。
其餘的選項一般是這種形式:
sentinel [option_name] [master_name] [option_value]
而且用於下面的目的:
其餘的選項在本文檔其餘部分有描述,而且在示例sentinel.conf的備有文件裏有附帶說明。
全部的Sentinel參數在運行時可使用SENTINEL SET命令更改。查看在運行時從新配置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 | +-------------+ +-------------+
還要注意:
注意永遠不會顯示的設置只是使用了兩個哨兵,由於爲了啓動故障轉移,Sentinel老是須要和其餘大多數的Sentinel通訊。
+----+ +----+ | M1 |---------| R1 | | S1 | | S2 | +----+ +----+ Configuration: quorum = 1
注意爲了排列不一樣的故障轉移須要少數服從多數,而且稍後向全部的Sentinel傳播最新的配置。還要注意上面配置的故障轉移的能力,沒有任何協定,很是危險:
+----+ +------+ | M1 |----//-----| [M1] | | S1 | | S2 | +----+ +------+
在上面的配置中咱們使用完美的對稱方式建立了兩個master(假定S2能夠在未受權的狀況下進行故障轉移)。客戶端可能會不肯定往哪邊寫,而且沒有途徑知道何時分區配置是正確的,爲了預防一個永久的斷裂狀態。
全部請永遠部署至少三個Sentinel在三個不一樣的盒子裏。
這是個很是簡單的設置,它有簡單調整安全的優點。它基於三個盒子,每一個盒子同時運行一個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將會中止接收寫入操做。這是個權衡。
有時咱們只有兩個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接收寫入的時間。
在例3中若是客戶端少於3個就不能使用。在這個案例中咱們使用一個混合的設置:
+----+ +----+ | M1 |----+----| R1 | | S1 | | | S2 | +----+ | +----+ | +------+-----+ | | | | +----+ +----+ | C1 | | C2 | | S3 | | S4 | +----+ +----+ Configuration: quorum = 3
這裏和例3很是相似,可是這裏咱們在4個盒子裏運行四個哨兵。若是M1故障其餘的三個哨兵能夠執行故障轉移。
Docker使用一個叫端口映射的技術:程序運行在Docker容器能夠暴露一個不一樣端口。這很是有助於在相同的服務器上相同的時間使用相同的端口運行多個容器。
Docker不只僅能夠實現這個功能,還有其餘的設置能夠從新映射端口,有時是端口,有時是IP地址。
從新映射端口和地址有兩個問題:
本文接下來的章節裏,將逐步覆蓋關於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端口外,其餘所有相同。
上面的配置中須要注意一些事情:
一旦你啓動三個Sentinel,你將會看到一些消息日誌,像:
+monitor master mymaster 127.0.0.1 6379 quorum 2
這是Sentinel事件,若是你SUBSCRIBE事件名稱,你能夠經過Pub/Sub接收到各類事件。
Sentinel在故障檢測和轉移期間生產並記錄不一樣的事件。
開始使用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的信息。有一些是對於咱們很是有用的:
爲了更多的探索這個實例,你可能想嘗試下面的兩個命令:
SENTINEL slaves mymaster SENTINEL sentinels mymaster
第一個會打印鏈接到master的slave的信息,第二個是關於其餘Sentinel的信息。
咱們已經說明,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日誌,以應該能看到不少動做:
若是你再次訪問 mymaster 當前master的地址,最終你此次應該獲得一個不同的答案:
127.0.0.1:5000] SENTINEL get-master-addr-by-name mymaster 1) "127.0.0.1" 2) "6380"
到目前位置一切都順利,這個時候你能夠跳轉到建立Sentinel部署或者能夠閱讀更多信息瞭解全部的Sentinel命令和內部構建。
Sentinel 提供了一個AP以便於檢查它的狀態,檢查監控的master和slave的健康,訂閱接收特定的通知,和在運行時改變Sentinel配置。
Sentinel默認使用TCP端口26379(注意6379是標準的Redis端口)。Sentinels使用Redis協議接收命令,因此你可使用 redis-cli 或任何其餘的Redis客戶端和Sentinel通訊。
能夠直接查詢Sentinel檢查監控的Redis實例的狀態,查看它知道的其它Sentinel,等等。或者,使用Pub/Sub,能夠從Sentinel接收推送類型的通知,每次有事件發生,例如故障轉移,或者實例進入錯誤條件,等等。
下面是一系列的接收命令,而不是所有的命令,用於修改Sentinel配置。
從Redis 2.8.4開始,Sentinel提供了API以便於添加、刪除、或者修改指定master的配置。注意若是有多個Sentinel,應該申請更改全部的Redis Sentinel實例。這意味這修改一臺Sentinel不會在網絡上自動傳播到其餘的Sentinel實例。
下面是SENTINEL的子命令清單,用於修改Sentinel實例的配置。
下面是一個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配置監控當前活動的master。10秒以內Sentinel就會得到其餘的Sentinel列表和master的slave。
若是你須要一次添加多個Sentinel,建議添加一個以後再添加另外一個,在添加下一個以前等待其餘的Sentinel已經知道了第一個Sentinel。這有助於始終保證能夠在一個分區得到多數,在添加Sentinel過程當中發生故障的機會。
經過每添加一個Sentinel有一個30秒的延遲很是容易得到。
在這個過程的最後要使用命令SENTINEL MASTER mastername一邊檢查是否全部Sentinel贊成監控master的Sentinel的總數。
刪除Sentinel有點複雜:Sentinel永遠不會忘記見到過的Sentinel,即便它們在很長時間內不能到達,由於咱們不但願動態的改變須要受權的多數並建立一個新值。因此爲了刪除一個Sentinel應該在網絡分區裏執行如下步驟:
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本身的時候指定。
當Lua腳本運行時間超過配置的Lua腳本時間限制時,Redis實例返回-BUSY錯誤。在觸發故障轉移以前發生這種狀況時,Sentinel將嘗試發送一個 SCRIPT KILL命令,它只在腳本只讀的時候成功。
若是嘗試過這個以後實例還是一個錯誤狀態,最後就會啓動故障轉移。
Redis實例有一個salve-priority的配置參數。這個信息暴露在Redis slave的 INFO 輸出裏,Sentinel使用它以便於在可用的salves中獲取slave進行故障轉移:
例如若是有一個slave S1在當前master的同一個數據中心,而且另外一個salve S2在另外一個數據中心,能夠設置S1的優先級爲10,S2的優先級爲100,因此若是master故障而且S1和S2均可用,S1將會被優先選擇。
瞭解關於slave選擇的更多信息,請參考 本文檔的 slave選擇和優先級部分。
當master配置要求從客戶端提供密碼做爲安全措施時,slave也須要知道這個密碼以便於master的身份驗證並創建master-slave之間的鏈接用於異步複製協議。
經過如下配置指令能夠實現:
當使用Sentinel時,沒有單獨的master,由於在故障轉移以後slave能夠改變master的角色,而且老master能夠被從新配置爲slave,因此你要作的是在master和slaves的全部實例裏都配置上上面的指令。
這一般也是一個理智的設置由於你不僅是想保護master裏的數據,在slave裏也是同樣。
然而在一些罕見的狀況下你須要slave不進行身份驗證就能夠訪問,你能夠將slave的優先級設置爲0,放置這個slave升級爲master,並在這個slave裏只配置masterauth指令,不用requirepass指令,以便於沒有受權的客戶端也能夠訪問。
Sentinel須要顯示的客戶端支持,除非系統被配置爲執行腳本對全部請求執行重定向到新master實例。客戶端類庫的實現話題在文檔Sentinel clients guidelines有覆蓋。
接下來的部分咱們將會涉及Sentinel怎麼工做的一些細節,沒有依靠實現細節和算法並會在本文檔的其餘部分涉及。
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的響應是下面的其中之一:
任何其餘的響應都視爲無效。可是注意一個合理的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狀態不會被選中晉級。
Sentinel保持與其餘Sentinel的鏈接以便於相互的檢查可用性,並傳輸消息。然而你不須要在每一個Sentinel實例裏配置其餘Sentinel的地址,由於Sentinel使用Redis實例的發佈/訂閱功能用於發現監控相同master和slave的其餘Sentinel。
這個功能由向_sentinel_:hello通道發送問候消息實現。
一樣你不須要配置master附加的slave列表,由於Sentinel會自動發現。
即便不進行故障轉移,Sentinel也會一直嘗試設置當前配置。特別的:
Sentinels從新配置slaves,有時必須監控錯誤配置,比周期性的廣播新配置要好。
Sentinel使用狀態配置信息在接收更新以前嘗試改變slaves配置。
還要注意怎樣嘗試利用當前配置防止故障分區:
在這個部分要記住的重要的是:Sentinel是一個系統,每一個進程一直嘗試利用最後一個合理的配置設置監控的實例。
當Sentinel實例準備執行故障轉移時,因爲master在ODOWN狀態且從多數的Sentinel實例接收到受權,須要選擇一個適當的slave。
選擇過程會評估slave下面的信息:
發現Slave從master斷開超過10倍的超時時間,加上Sentinel認爲master不可用的時間,就認爲不適合故障轉移並跳過。
更嚴格的條件,slave的INFO輸出信息顯示從master斷開超過:
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state
被認爲是不適合的並徹底忽略。
Slave選擇只認爲經過上面的測試,並在上面的標準基礎上排序:
若是要強烈的匹配,Redis master和slaves都要配置 salve-priority。不然全部的實例可使用默認的run ID運行(建議這樣設置,由於這比經過複製偏移量選擇slave更感興趣)。
Redis實例能夠配置特定的slave-priority爲0用於永遠不讓sentinel選舉爲master。可是用這種方式配置slave會在故障轉移以後從新配置以便於複製新master的數據,不一樣的只是他永遠不會變成一個master。
在接下來的部分咱們將會探究Sentinel特性的細節。用戶不須要關注全部的細節,可是深度理解能夠幫你更有效的開發和操做Sentinel。
上面的章節中展現了每一個監控的master都關聯一個quorum配置。它指定須要商定master不可及或錯誤條件Sentinel進程數量以便於觸發故障轉移。
然而,觸發故障轉移以後,爲了真正的執行故障轉移,至少大多數的Sentinel必須受權Sentinel進行故障轉移。若是隻有少數的Sentinel存在,Sentinel將永遠不會執行故障轉移。
讓咱們試着使事情更清晰:
不一樣之處彷佛很小,可是很容易理解和使用。例如若是你有5個Sentinel實例,quorum設置爲2,一旦2個Sentinel認爲master不可及就會觸發故障轉移,可是隻有其中一個Sentinel獲得至少3個贊成的時候才能夠故障轉移。
若是把quorum配置爲5,全部的Sentinel都必須統一master的錯誤條件,且從全部的Sentinel獲得受權才能夠故障轉移。
這意味着quorum能夠經過兩個方式用於調整Sentinel:
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有三個不一樣的角色:
爲了定義系統特性咱們必須考慮這三個角色。
下面是一個簡單的有三個節點的網絡,每一個節點運行一個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,而且全部在分區期間寫入的數據都將會丟失。
根據你的配置你可能不想讓這個事情發生:
由於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配置文件裏。例如每次接收一個新配置,或者建立,配置文件會和配置epoch一塊兒持久化到硬盤上。
這意味着在中止和重啓Sentinel進程的時候是安全的。
Redis Sentinel嚴重依賴於計算機時間:例如爲了理解一個實例是否可用,它記錄上次成功響應PING命令的時間,並和當前時間對比分析已經多久了。
然而若是計算機時間意外的改變了,或者計算機很是忙,或者進程因爲某些緣由損壞,Sentinel可能會有一個意想不到的行爲。
TILT模式是一個特殊的 "protection" 模式,當檢測到能夠下降系統可靠性怪異現象時,Sentinel能夠進入 "protection" 模式。Sentinel時間計數器通常每秒調用10次,因此咱們指望大約100毫秒在兩個調用之間中斷。
什麼哨兵調用中判定時器,並和當前調用對比:若是時常是負數或出乎意料的大(2秒或更大)就進入TILT模式。
當進入TILT模式,Sentinel將繼續監控每件事,除了:
一切恢復正常30秒以後,就退出TILT模式。
注意在某些方面TILT模式可使用不少內核支持的單調時鐘API替換。然而仍不清楚這是不是一個好的解決方案,由於當前系統避免問題的過程只是在很長時間暫停或不執行調度。