本文轉載自:http://shift-alt-ctrl.iteye.com/blog/1884370redis
文中的配置例子,還有failover過程當中觸發的訂閱事件具備很好的參考價值。app
Redis sentinel(哨兵)模塊已經被集成在redis2.4+的版本中,儘管目前不是release,不過能夠嘗試去使用和了解,事實上sentinel仍是有點複雜的.
sentinel主要功能就是爲Redis M-S(master,slaves)集羣提供了1)master存活檢測 2)集羣中M-S服務監控 3) 自動故障轉移,M-S角色轉換等能力,從一個方面說是提升了redis集羣的可用性.tcp
通常狀況下,最小M-S單元各有一個maste和slave組成,當master失效後,sentinel能夠幫助咱們自動將slave提高爲master;有了sentinel組件,能夠減小系統管理員的人工切換slave的操做過程.ui
sentinel的一些設計思路和zookeeper很是相似,事實上,你能夠不使用sentinel,而是本身開發一個監控redis的zk客戶端也可以完成相應的設計要求.spa
一.環境部署翻譯
準備3個redis服務,簡單構建一個小的M-S環境;它們各自的redis.conf配置項中,除了port不一樣外,要求其餘的配置徹底同樣(包括aof/snap,memory,rename以及受權密碼等);緣由是基於sentinel作故障轉移,全部的server運行機制都必須同樣,它們只不過在運行時"角色"不一樣,並且它們的角色可能在故障時會被轉換;slave在某些時刻也會成爲master,儘管在通常狀況下,slave的數據持久方式常常採起snapshot,而master爲aof,不過基於sentinel以後,slave和master均要採起aof(經過bgsave,手動觸發snapshot備份).設計
1) redis.conf:
server
- ##redis.conf
- ##redis-0,默認爲master
- port 6379
- ##受權密碼,請各個配置保持一致
- requirepass 012_345^678-90
- masterauth 012_345^678-90
- ##暫且禁用指令重命名
- ##rename-command
- ##開啓AOF,禁用snapshot
- appendonly yes
- save 「」
- ##slaveof no one
- slave-read-only yes
- ##redis.conf
- ##redis-1,經過啓動參數配置爲slave,配置文件保持獨立
- port 6479
- slaveof 127.0.0.1 6379
- ##-----------其餘配置和master保持一致-----------##
- ##redis.conf
- ##redis-1,經過啓動參數配置爲slave,配置文件保持獨立
- port 6579
- slaveof 127.0.0.1 6379
- ##-----------其餘配置和master保持一致-----------##
2) sentinel.confblog
請首先在各個redis服務中sentinel.conf同目錄下新建local-sentinel.conf,並將複製以下配置信息.排序
- ##redis-0
- ##sentinel實例之間的通信端口
- port 26379
- sentinel monitor def_master 127.0.0.1 6379 2
- sentinel auth-pass def_master 012_345^678-90
- sentinel down-after-milliseconds def_master 30000
- sentinel can-failover def_master yes
- sentinel parallel-syncs def_master 1
- sentinel failover-timeout def_master 900000
- ##redis-1
- port 26479
- ##--------其餘配置同上-------##
- ##redis-2
- port 26579
- ##--------其餘配置同上-------#
3) 啓動與檢測
- ##redis-0(默認爲master)
- > ./redis-server --include ../redis.conf
- ##啓動sentinel組件
- > ./redis-sentinel ../local-sentinel.conf
按照上述指令,依次啓動redis-0,redis-1,redis-2;在啓動redis-1和redis-2的時候,你會發如今redis-0的sentinel控制檯會輸出"+sentinel ..."字樣,表示有新的sentinel實例加入到監控.不過此處須要提醒,首次構建sentinel環境時,必須首先啓動master機器.
此後你可使用任意一個"redis-cli"窗口,輸入"INFO"命令,能夠查看當前server的狀態:
- > ./redis-cli -h 127.0.0.1 -p 6379
- ##以下爲打印信息摘要:
- #Replication
- role:master
- connected_salves:2
- slave0:127.0.0.1,6479,online
- slave1:127.0.0.1.6579,online
"INFO"指令將會打印完整的服務信息,包括集羣,咱們只須要關注"replication"部分,這部分信息將會告訴咱們"當前server的角色"以及指向它的全部的slave信息.能夠經過在任何一個slave上,使用"INFO"指令得到當前slave所指向的master信息.
"INFO"指令不只能夠幫助咱們得到集羣的狀況,固然sentinel組件也是使用"INFO"作一樣的事情.
當上述部署環境穩定後,咱們直接關閉redis-0,在等待"down-after-milliseconds"秒以後(30秒),redis-0/redis-1/redis-2的sentinel窗口會當即打印"+sdown""+odown""+failover""+selected-slave""+promoted-slave""+slave-reconf"等等一系列指令,這些指令標明當master失效後,sentinel組件進行failover的過程.
當環境再次穩定後,咱們發現,redis-1被提高("promoted")爲master,且redis-2也經過"slave-reconf"過程以後跟隨了redis-1.
若是此後想再次讓redis-0加入集羣,你須要首先經過"INFO"指令找到當前的masterip + port,並在啓動指令中明確指明slaveof參數:
- > ./redis-server --include ../redis.conf --slaveof 127.0.0.1 6479
sentinel實例須要全程處於啓動狀態,若是隻啓動server而不啓動相應的sentinel,仍然不能確保server可以正確的被監控和管理.
二. sentinel原理
首先解釋2個名詞:SDOWN和ODOWN.
- SDOWN:subjectively down,直接翻譯的爲"主觀"失效,即當前sentinel實例認爲某個redis服務爲"不可用"狀態.
- ODOWN:objectively down,直接翻譯爲"客觀"失效,即多個sentinel實例都認爲master處於"SDOWN"狀態,那麼此時master將處於ODOWN,ODOWN能夠簡單理解爲master已經被集羣肯定爲"不可用",將會開啓failover.
SDOWN適合於master和slave,可是ODOWN只會使用於master;當slave失效超過"down-after-milliseconds"後,那麼全部sentinel實例都會將其標記爲"SDOWN".
1) SDOWN與ODOWN轉換過程:
- 每一個sentinel實例在啓動後,都會和已知的slaves/master以及其餘sentinels創建TCP鏈接,並週期性發送PING(默認爲1秒)
- 在交互中,若是redis-server沒法在"down-after-milliseconds"時間內響應或者響應錯誤信息,都會被認爲此redis-server處於SDOWN狀態.
- 若是2)中SDOWN的server爲master,那麼此時sentinel實例將會向其餘sentinel間歇性(一秒)發送"is-master-down-by-addr <ip> <port>"指令並獲取響應信息,若是足夠多的sentinel實例檢測到master處於SDOWN,那麼此時當前sentinel實例標記master爲ODOWN...其餘sentinel實例作一樣的交互操做.配置項"sentinel monitor <mastername> <masterip> <masterport> <quorum>",若是檢測到master處於SDOWN狀態的slave個數達到<quorum>,那麼此時此sentinel實例將會認爲master處於ODOWN.
- 每一個sentinel實例將會間歇性(10秒)向master和slaves發送"INFO"指令,若是master失效且沒有新master選出時,每1秒發送一次"INFO";"INFO"的主要目的就是獲取並確認當前集羣環境中slaves和master的存活狀況.
- 通過上述過程後,全部的sentinel對master失效達成一致後,開始failover.
2) Sentinel與slaves"自動發現"機制:
在sentinel的配置文件中(local-sentinel.conf),都指定了port,此port就是sentinel實例偵聽其餘sentinel實例創建連接的端口.在集羣穩定後,最終會每一個sentinel實例之間都會創建一個tcp連接,此連接中發送"PING"以及相似於"is-master-down-by-addr"指令集,可用用來檢測其餘sentinel實例的有效性以及"ODOWN"和"failover"過程當中信息的交互.
在sentinel之間創建鏈接以前,sentinel將會盡力和配置文件中指定的master創建鏈接.sentinel與master的鏈接中的通訊主要是基於pub/sub來發布和接收信息,發佈的信息內容包括當前sentinel實例的偵聽端口:
- +sentinel sentinel 127.0.0.1:26579 127.0.0.1 26579 ....
發佈的主題名稱爲"__sentinel__:hello";同時sentinel實例也是"訂閱"此主題,以得到其餘sentinel實例的信息.因而可知,環境首次構建時,在默認master存活的狀況下,全部的sentinel實例能夠經過pub/sub便可得到全部的sentinel信息,此後每一個sentinel實例便可以根據+sentinel信息中的"ip+port"和其餘sentinel逐個創建tcp鏈接便可.不過須要提醒的是,每一個sentinel實例均會間歇性(5秒)向"__sentinel__:hello"主題中發佈本身的ip+port,目的就是讓後續加入集羣的sentinel實例也能或獲得本身的信息.
根據上文,咱們知道在master有效的狀況下,便可經過"INFO"指令得到當前master中已有的slave列表;此後任何slave加入集羣,master都會向"主題中"發佈"+slave 127.0.0.1:6579 ..",那麼全部的sentinel也將當即得到slave信息,並和slave創建連接並經過PING檢測其存活性.
補充一下,每一個sentinel實例都會保存其餘sentinel實例的列表以及現存的master/slaves列表,各自的列表中不會有重複的信息(不可能出現多個tcp鏈接),對於sentinel將使用ip+port作惟一性標記,對於master/slaver將使用runid作惟一性標記,其中redis-server的runid在每次啓動時都不一樣.
3) 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過程將沒法繼續.
4) 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。