本專欄與Redis相關的文章redis
Redis Sentinel機制與用法(一)
Redis Sentinel機制與用法(二)
Jedis的JedisSentinelPool源代碼分析
Jedis的Sharded源代碼分析
Redis 主從 Replication 的配置
詳解Redis SORT命令
JedisCommand接口說明算法
本文參考翻譯自 《Redis Sentinel Documentation》
Redis-Sentinel是Redis官方推薦的高可用性(HA)解決方案,當用Redis作Master-slave的高可用方案時,假如master宕機了,Redis自己(包括它的不少客戶端)都沒有實現自動進行主備切換,而Redis-sentinel自己也是一個獨立運行的進程,它能監控多個master-slave集羣,發現master宕機後能進行自懂切換。segmentfault
它的主要功能有如下幾點緩存
<br/>安全
很顯然,只使用單個sentinel進程來監控redis集羣是不可靠的,當sentinel進程宕掉後(sentinel自己也有單點問題,single-point-of-failure)整個集羣系統將沒法按照預期的方式運行。因此有必要將sentinel集羣,這樣有幾個好處:微信
Sentinel當前最新的穩定版本稱爲Sentinel 2(與以前的Sentinel 1區分開來)。隨着redis2.8的安裝包一塊兒發行。安裝完Redis2.8後,能夠在redis2.8/src/裏面找到Redis-sentinel的啓動程序。網絡
強烈建議:
若是你使用的是redis2.6(sentinel版本爲 sentinel 1),你最好應該使用redis2.8版本的 sentinel 2,由於sentinel 1有不少的Bug,已經被官方棄用,因此強烈建議使用redis2.8以及sentinel 2。
運行sentinel有兩種方式:併發
第一種異步
redis-sentinel /path/to/sentinel.conf
第二種spa
redis-server /path/to/sentinel.conf --sentinel
以上兩種方式,都必須指定一個sentinel的配置文件sentinel.conf,若是不指定,將沒法啓動sentinel。sentinel默認監聽26379端口,因此運行前必須肯定該端口沒有被別的進程佔用。
Redis源碼包中包含了一個sentinel.conf文件做爲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
上面的配置項配置了兩個名字分別爲mymaster和resque的master,配置文件只須要配置master的信息就好啦,不用配置slave的信息,由於slave可以被自動檢測到(master節點會有關於slave的消息)。須要注意的是,配置文件在sentinel運行期間是會被動態修改的,例如當發生主備切換時候,配置文件中的master會被修改成另一個slave。這樣,以後sentinel若是重啓時,就能夠根據這個配置來恢復其以前所監控的redis集羣的狀態。
接下來咱們將一行一行地解釋上面的配置項:
sentinel monitor mymaster 127.0.0.1 6379 2
這一行表明sentinel監控的master的名字叫作mymaster,地址爲127.0.0.1:6379,行尾最後的一個2表明什麼意思呢?咱們知道,網絡是不可靠的,有時候一個sentinel會由於網絡堵塞而誤覺得一個master redis已經死掉了,當sentinel集羣式,解決這個問題的方法就變得很簡單,只須要多個sentinel互相溝通來確認某個master是否真的死了,這個2表明,當集羣中有2個sentinel認爲master死了時,才能真正認爲該master已經不可用了。(sentinel集羣中各個sentinel也有互相通訊,經過gossip協議)。
除了第一行配置,咱們發現剩下的配置都有一個統一的格式:
sentinel <option_name> <master_name> <option_value>
接下來咱們根據上面格式中的option_name一個一個來解釋這些配置項:
sentinel會向master發送心跳PING來確認master是否存活,若是master在「必定時間範圍」內不迴應PONG 或者是回覆了一個錯誤消息,那麼這個sentinel會主觀地(單方面地)認爲這個master已經不可用了(subjectively down, 也簡稱爲SDOWN)。而這個down-after-milliseconds就是用來指定這個「必定時間範圍」的,單位是毫秒。
不過須要注意的是,這個時候sentinel並不會立刻進行failover主備切換,這個sentinel還須要參考sentinel集羣中其餘sentinel的意見,若是超過某個數量的sentinel也 主觀地認爲該master死了,那麼這個master就會被 客觀地(注意哦,此次不是主觀,是客觀,與剛纔的subjectively down相對,此次是objectively down,簡稱爲ODOWN)認爲已經死了。須要一塊兒作出決定的sentinel數量在上一條配置中進行配置。
在發生failover主備切換時,這個選項指定了最多能夠有多少個slave同時對新的master進行同步,這個數字越小,完成failover所需的時間就越長,可是若是這個數字越大,就意味着越多的slave由於replication而不可用。能夠經過將這個值設爲 1 來保證每次只有一個slave處於不能處理命令請求的狀態。
其餘配置項在sentinel.conf中都有很詳細的解釋。
全部的配置均可以在運行時用命令SENTINEL SET command
動態修改。
前面咱們談到,當一個master被sentinel集羣監控時,須要爲它指定一個參數,這個參數指定了當須要判決master爲不可用,而且進行failover時,所須要的sentinel數量,本文中咱們暫時稱這個參數爲票數
不過,當failover主備切換真正被觸發後,failover並不會立刻進行,還須要sentinel中的大多數sentinel受權後才能夠進行failover。
當ODOWN時,failover被觸發。failover一旦被觸發,嘗試去進行failover的sentinel會去得到「大多數」sentinel的受權(若是票數比大多數還要大的時候,則詢問更多的sentinel)
這個區別看起來很微妙,可是很容易理解和使用。例如,集羣中有5個sentinel,票數被設置爲2,當2個sentinel認爲一個master已經不可用了之後,將會觸發failover,可是,進行failover的那個sentinel必須先得到至少3個sentinel的受權才能夠實行failover。
若是票數被設置爲5,要達到ODOWN狀態,必須全部5個sentinel都主觀認爲master爲不可用,要進行failover,那麼得得到全部5個sentinel的受權。
爲何要先得到大多數sentinel的承認時才能真正去執行failover呢?
當一個sentinel被受權後,它將會得到宕掉的master的一份最新配置版本號,當failover執行結束之後,這個版本號將會被用於最新的配置。由於大多數sentinel都已經知道該版本號已經被要執行failover的sentinel拿走了,因此其餘的sentinel都不能再去使用這個版本號。這意味着,每次failover都會附帶有一個獨一無二的版本號。咱們將會看到這樣作的重要性。
並且,sentinel集羣都遵照一個規則:若是sentinel A推薦sentinel B去執行failover,A會等待一段時間後,自行再次去對同一個master執行failover,這個等待的時間是經過failover-timeout
配置項去配置的。從這個規則能夠看出,sentinel集羣中的sentinel不會再同一時刻併發去failover同一個master,第一個進行failover的sentinel若是失敗了,另一個將會在必定時間內進行從新進行failover,以此類推。
redis sentinel保證了活躍性:若是大多數sentinel可以互相通訊,最終將會有一個被受權去進行failover.
redis sentinel也保證了安全性:每一個試圖去failover同一個master的sentinel都會獲得一個獨一無二的版本號。
一旦一個sentinel成功地對一個master進行了failover,它將會把關於master的最新配置經過廣播形式通知其它sentinel,其它的sentinel則更新對應master的配置。
一個faiover要想被成功實行,sentinel必須可以向選爲master的slave發送SLAVE OF NO ONE
命令,而後可以經過INFO
命令看到新master的配置信息。
當將一個slave選舉爲master併發送SLAVE OF NO ONE
`後,即便其它的slave還沒針對新master從新配置本身,failover也被認爲是成功了的,而後全部sentinels將會發布新的配置信息。
新配在集羣中相互傳播的方式,就是爲何咱們須要當一個sentinel進行failover時必須被受權一個版本號的緣由。
每一個sentinel使用##發佈/訂閱##的方式持續地傳播master的配置版本信息,配置傳播的##發佈/訂閱##管道是:__sentinel__:hello
。
由於每個配置都有一個版本號,因此以版本號最大的那個爲標準。
舉個栗子:假設有一個名爲mymaster的地址爲192.168.1.50:6379。一開始,集羣中全部的sentinel都知道這個地址,因而爲mymaster的配置打上版本號1。一段時候後mymaster死了,有一個sentinel被受權用版本號2對其進行failover。若是failover成功了,假設地址改成了192.168.1.50:9000,此時配置的版本號爲2,進行failover的sentinel會將新配置廣播給其餘的sentinel,因爲其餘sentinel維護的版本號爲1,發現新配置的版本號爲2時,版本號變大了,說明配置更新了,因而就會採用最新的版本號爲2的配置。
這意味着sentinel集羣保證了第二種活躍性:一個可以互相通訊的sentinel集羣最終會採用版本號最高且相同的配置。
sentinel對於不可用有兩種不一樣的見解,一個叫主觀不可用(SDOWN),另一個叫客觀不可用(ODOWN)。SDOWN是sentinel本身主觀上檢測到的關於master的狀態,ODOWN須要必定數量的sentinel達成一致意見才能認爲一個master客觀上已經宕掉,各個sentinel之間經過命令SENTINEL is_master_down_by_addr
來得到其它sentinel對master的檢測結果。
從sentinel的角度來看,若是發送了PING心跳後,在必定時間內沒有收到合法的回覆,就達到了SDOWN的條件。這個時間在配置中經過is-master-down-after-milliseconds
參數配置。
當sentinel發送PING後,如下回復之一都被認爲是合法的:
PING replied with +PONG. PING replied with -LOADING error. PING replied with -MASTERDOWN error.
其它任何回覆(或者根本沒有回覆)都是不合法的。
從SDOWN切換到ODOWN不須要任何一致性算法,只須要一個gossip協議:若是一個sentinel收到了足夠多的sentinel發來消息告訴它某個master已經down掉了,SDOWN狀態就會變成ODOWN狀態。若是以後master可用了,這個狀態就會相應地被清理掉。
正如以前已經解釋過了,真正進行failover須要一個受權的過程,可是全部的failover都開始於一個ODOWN狀態。
ODOWN狀態只適用於master,對於不是master的redis節點sentinel之間不須要任何協商,slaves和sentinel不會有ODOWN狀態。
雖然sentinel集羣中各個sentinel都互相鏈接彼此來檢查對方的可用性以及互相發送消息。可是你不用在任何一個sentinel配置任何其它的sentinel的節點。由於sentinel利用了master的發佈/訂閱機制去自動發現其它也監控了統一master的sentinel節點。
經過向名爲__sentinel__:hello
的管道中發送消息來實現。
一樣,你也不須要在sentinel中配置某個master的全部slave的地址,sentinel會經過詢問master來獲得這些slave的地址的。
每一個sentinel經過向每一個master和slave的發佈/訂閱頻道__sentinel__:hello
每秒發送一次消息,來宣佈它的存在。
每一個sentinel也訂閱了每一個master和slave的頻道__sentinel__:hello
的內容,來發現未知的sentinel,當檢測到了新的sentinel,則將其加入到自身維護的master監控列表中。
每一個sentinel發送的消息中也包含了其當前維護的最新的master配置。若是某個sentinel發現
本身的配置版本低於接收到的配置版本,則會用新的配置更新本身的master配置。
在爲一個master添加一個新的sentinel前,sentinel老是檢查是否已經有sentinel與新的sentinel的進程號或者是地址是同樣的。若是是那樣,這個sentinel將會被刪除,而把新的sentinel添加上去。
redis sentinel集羣的配置的一致性模型爲最終一致性,集羣中每一個sentinel最終都會採用最高版本的配置。然而,在實際的應用環境中,有三個不一樣的角色會與sentinel打交道:
爲了考察整個系統的行爲咱們必須同時考慮到這三個角色。
下面有個簡單的例子,有三個主機,每一個主機分別運行一個redis和一個sentinel:
+-------------+ | Sentinel 1 | <--- Client A | Redis 1 (M) | +-------------+ | | +-------------+ | +------------+ | Sentinel 2 |-----+-- / partition / ----| Sentinel 3 | <--- Client B | Redis 2 (S) | | Redis 3 (M)| +-------------+ +------------+
在這個系統中,初始狀態下redis3是master, redis1和redis2是slave。以後redis3所在的主機網絡不可用了,sentinel1和sentinel2啓動了failover並把redis1選舉爲master。
Sentinel集羣的特性保證了sentinel1和sentinel2獲得了關於master的最新配置。可是sentinel3依然持着的是就的配置,由於它與外界隔離了。
當網絡恢復之後,咱們知道sentinel3將會更新它的配置。可是,若是客戶端所鏈接的master被網絡隔離,會發生什麼呢?
客戶端將依然能夠向redis3寫數據,可是當網絡恢復後,redis3就會變成redis的一個slave,那麼,在網絡隔離期間,客戶端向redis3寫的數據將會丟失。
也許你不會但願這個場景發生:
由於redis採用的是異步複製,在這樣的場景下,沒有辦法避免數據的丟失。然而,你能夠經過如下配置來配置redis3和redis1,使得數據不會丟失。
min-slaves-to-write 1 min-slaves-max-lag 10
經過上面的配置,當一個redis是master時,若是它不能向至少一個slave寫數據(上面的min-slaves-to-write指定了slave的數量),它將會拒絕接受客戶端的寫請求。因爲複製是異步的,master沒法向slave寫數據意味着slave要麼斷開鏈接了,要麼不在指定時間內向master發送同步數據的請求了(上面的min-slaves-max-lag指定了這個時間)。
snetinel的狀態會被持久化地寫入sentinel的配置文件中。每次當收到一個新的配置時,或者新建立一個配置時,配置會被持久化到硬盤中,並帶上配置的版本戳。這意味着,能夠安全的中止和重啓sentinel進程。