Redis Sentinel 是一套用於管理Redis實例的分佈式系統,主要完成3項任務:
1. Monitoring:持續監控Redis master或slave實例的運行情況是否符合預期
2. Notification:若被監控的Redis實例運行異常,sentinel會通過API通知外界(人或程序)
3. Automation
failover:若master實例故障,sentinel會重新選主並啓動自動故障切換:選擇slave-priority最小的那個slave實例
並將其提升爲master,同時修改其它slave的配置,使其master配置項指向新的master,當old
master恢復重啓後,會自動降級爲new master的slave.最後,根據配置,Redis
Sentinel還會將新的master地址通知給當前正在訪問Redis的應用程序.
Raft分佈式算法
1. 主要用途:用於分佈式系統,系統容錯,以及選出領頭羊
2. 作者:Diego Ongaro,畢業於哈佛
3. 目前用到這個算法的項目有:
a. CoreOS
b. ectd : a distributed, consistent shared configuration
c. LogCabin : 分佈式存儲系統
d. redis sentinel : redis 的監控系統
Sentinel使用的Raft算法核心: 原則
1. 所有sentinel都有選舉的領頭羊的權利
2. 每個sentinel都會要求其他sentinel選舉自己爲領頭羊(主要由發現redis客觀下線的sentinel先發起選舉)
3. 每個sentinel只有一次選舉的機會
4. 採用先到先得的原則
5. 一旦加入到系統了,則不會自動清除(這一點很重要, why?)
6. 每個sentinel都有唯一的uid,不會因爲重啓而變更
7. 達到領頭羊的條件是 N/2 + 1個sentinel選擇了自己
8. 採用配置紀元,如果一次選舉出現腦裂,則配置紀元會遞增,進入下一次選舉,所有sentinel都會處於統一配置紀元,以最新的爲標準.
Sentinel 配置樣例
port 26379 dir /tmp sentinel monitor mymaster 127.0.0.1 6379 2 sentinel down-after-milliseconds mymaster 30000 sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 180000 sentinel notification-script myredis <script-path>
其中:
port: 指定sentinel的偵聽端口(即與redis server或client建立tcp連接的端口)
dir: 工作路徑,sentinel一般指定/tmp比較簡單
monitor:
指定sentinel要monitor的redis實例,包括一個redis實例的別名(alias)及redis實例的ip+port,該行最後的數字
2表示至少2個setinel實例同時檢測到redis server異常時,纔將redis server的狀態判決爲real
fail.也即,若這裏配置爲2,但實際部署中sentinel只部署了1套,則即使redis實例已經掛掉,sentinel也不會給出任何警告.這一
點需要特別引起注意.
down-after-milliseconds: 指定sentinel監控到redis實例持續異常多長時間後,會判決其狀態爲down.若實際業務需要sentinel儘快判決出redis實例異常,則該值可適當配小.
failover-timeout:
若sentinel在該配置值內未能完成failover操作(即故障時master/slave自動切換),則認爲本次failover失敗.該配置有
4個用途,具體可參考sentinel.conf中的說明,限於篇幅,此處不再贅述.
parallel-syncs: 指定failover過程中,同時被sentinel reconfigure的最大slave實例數.由於reconfigure過程中,對應的slave會中斷響應客戶端請求,故爲避免所有的slave同時不可用,該值需適當配小.
notification-script: 指定sentinel檢測到master-name指向的實例異常時,調用的報警腳本.該配置項可選,但線上系統建議配置.
啓動 sentinel的方法
當前Redis stable版已經自帶了redis-sentinel這個工具.雖然 Redis Sentinel
已經提供了一個單獨的可執行文件 redis-sentinel , 但實際上它只是一個運行在特殊模式下的 Redis實例, 你可以在啓動一個普通
Redis實例時通過給定 –sentinel 選項來啓動 Redis Sentinel 實例.也就是說:
redis-sentinel /path/to/sentinel.conf
等同於
redis-server /path/to/sentinel.conf –sentinel
其中sentinel.conf是redis的配置文件,Redis sentinel會需要寫入配置文件來保存sentinel的當前狀態.當配置文件無法寫入時,Sentinel啓動失敗.
sentinel 測試
實驗環境 < one master / Three slaves / two sentinels >:
a. one master(slave-priority爲90)部署在ip爲192.168.9.10的機器上;
b.Three slaves(slave-priority分別爲100)的均部署在ip爲192.168.9.70的機器上;
c. 啓用兩個sentinel進程監控redis集羣狀態
配置 sentinel
Sentinel可以通過master Redis實例來獲得它的從實例的信息.所以每一個Sentinel只配置主實例的監控即可.Sentinel之間端口有所不同.
port 6666 daemonize yes logfile "/var/log/redis/sentinel-6666.log" #master 1111 sentinel monitor master-1111 192.168.9.10 11111 1 sentinel config-epoch master-1111 6 sentinel leader-epoch master-1111 6 sentinel known-slave master-1111 192.168.9.70 2222
啓動 sentinel
配置文件修改完成後,啓動各監控進程即可,例如:
redis-server /etc/redis/sentinel-6666.conf
連接Sentinel和主動failover
在默認情況下,Sentinel 使用TCP端口26379(普通 Redis 服務器使用的是 6379).
Sentinel 接受 Redis 協議格式的命令請求,所以你可以使用 redis-cli 或者任何其他 Redis 客戶端來與 Sentinel 進行通訊.
有兩種方式可以和 Sentinel 進行通訊:
第一種方法是通過直接發送命令來查詢被監視 Redis 服務器的當前狀態, 以及進行主動轉移等操作.這些命令包括:
SENTINEL masters
列出所有被監視的主Redis服務實例,以及這些主服務實例的當前狀態.
SENTINEL slaves
列出給定主服務實例的所有從實例,以及這些從實例的當前狀態.
SENTINEL get-master-addr-by-name
返回給定名字的主實例的 IP 地址和端口號. 如果這個主實例正在執行故障轉移操作, 或者針對這個主實例的故障轉移操作已經完成, 那麼這個命令返回新的主服務器的 IP 地址和端口號.
SENTINEL reset:
重置所有名字和給定模式 pattern 相匹配的主服務器. pattern 參數是一個 Glob 風格的模式. 重置操作清除該sentinel的所保存的所有狀態信息,並進行一次重新的發現過程.
SENTINEL failover
進行一次主動的failover.即在不詢問其他 Sentinel 意見的情況下, 強制開始一次自動故障遷移 .發起故障轉移的 Sentinel
會向其他 Sentinel 發送一個新的配置,其他 Sentinel 會根據這個配置進行相應的更新.
^_^[17:19:25][root@master01 ~]#redis-cli -p 6666 redis 127.0.0.1:6666> SENTINEL masters 1) 1) "name" 2) "master-1111" 3) "ip" 4) "192.168.9.10" 5) "port" 6) "1111" 7) "runid" 8) "5d6c2f08547ffe9446eb54c85dc40959e66b203d" 9) "flags" 10) "master" 11) "pending-commands" 12) "0" 13) "last-ping-sent" 14) "0" 15) "last-ok-ping-reply" 16) "947" 17) "last-ping-reply" 18) "947" 19) "down-after-milliseconds" 20) "30000" 21) "info-refresh" 22) "6259" 23) "role-reported" 24) "master" 25) "role-reported-time" 26) "126884" 27) "config-epoch" 28) "7" 29) "num-slaves" 30) "3" 31) "num-other-sentinels" 32) "1" 33) "quorum" 34) "1" 35) "failover-timeout" 36) "180000" 37) "parallel-syncs" 38) "1" redis 127.0.0.1:6666> SENTINEL slaves master-1111 1) 1) "name" 2) "192.168.9.10:1112" 3) "ip" 4) "192.168.9.10" 5) "port" 6) "1112" 7) "runid" 8) "" 9) "flags" 10) "s_down,slave,disconnected" 11) "pending-commands" 12) "0" 13) "last-ping-sent" 14) "215549" 15) "last-ok-ping-reply" 16) "215549" 17) "last-ping-reply" 18) "215549" 19) "s-down-time" 20) "185544" 21) "down-after-milliseconds" 22) "30000" 23) "info-refresh" 24) "1458206565223" 25) "role-reported" 26) "slave" 27) "role-reported-time" 28) "215549" 29) "master-link-down-time" 30) "0" 31) "master-link-status" 32) "err" 33) "master-host" 34) "?" 35) "master-port" 36) "0" 37) "slave-priority" 38) "100" 39) "slave-repl-offset" 40) "0" 2) 1) "name" 2) "192.168.9.70:2222" 3) "ip" 4) "192.168.9.70" 5) "port" 6) "2222" 7) "runid" 8) "" 9) "flags" 10) "s_down,slave,disconnected" 11) "pending-commands" 12) "0" 13) "last-ping-sent" 14) "215549" 15) "last-ok-ping-reply" 16) "215549" 17) "last-ping-reply" 18) "215549" 19) "s-down-time" 20) "185544" 21) "down-after-milliseconds" 22) "30000" 23) "info-refresh" 24) "1458206565223" 25) "role-reported" 26) "slave" 27) "role-reported-time" 28) "215549" 29) "master-link-down-time" 30) "0" 31) "master-link-status" 32) "err" 33) "master-host" 34) "?" 35) "master-port" 36) "0" 37) "slave-priority" 38) "100" 39) "slave-repl-offset" 40) "0" 3) 1) "name" 2) "192.168.9.70:2223" 3) "ip" 4) "192.168.9.70" 5) "port" 6) "2223" 7) "runid" 8) "9987aebafc55d750145a61f9109cf7d9fb7c8613" 9) "flags" 10) "slave" 11) "pending-commands" 12) "0" 13) "last-ping-sent" 14) "0" 15) "last-ok-ping-reply" 16) "372" 17) "last-ping-reply" 18) "372" 19) "down-after-milliseconds" 20) "30000" 21) "info-refresh" 22) "4616" 23) "role-reported" 24) "slave" 25) "role-reported-time" 26) "215549" 27) "master-link-down-time" 28) "0" 29) "master-link-status" 30) "ok" 31) "master-host" 32) "192.168.9.10" 33) "master-port" 34) "1111" 35) "slave-priority" 36) "100" 37) "slave-repl-offset" 38) "29082" 查看當前的master redis 127.0.0.1:6666> SENTINEL get-master-addr-by-name master-1111 1) "192.168.9.10" 2) "1111"
使用發佈與訂閱功能, 通過接收 Sentinel 發送的通知: 當執行故障轉移操作, 或者某個被監視的實例被判斷爲主觀下線或者客觀下線時, Sentinel 就會發送相應的信息.
一個頻道能夠接收和這個頻道的名字相同的事件. 比如說,名爲 +sdown 的頻道就可以接收所有實例進入主觀下線(SDOWN)狀態的事件.
通過執行 PSUBSCRIBE * 命令可以接收所有事件信息.例如:
^_^[17:50:13][root@master01 ~]#redis-cli -p 6666 info| grep 192 master0:name=master-1111,status=ok,address=192.168.9.10:1111,slaves=3,sentinels=2 ^_^[17:50:21][root@master01 ~]#redis-cli -p 6666 sentinel failover master-1111 OK @_@[17:50:09][root@master01 ~]#redis-cli -p 6666 redis 127.0.0.1:6666> SENTINEL get-master-addr-by-name master-1111 1) "192.168.9.10" 2) "1111" redis 127.0.0.1:6666> PSUBSCRIBE * Reading messages... (press Ctrl-C to quit) 1) "psubscribe" 2) "*" 3) (integer) 1 1) "pmessage" 2) "*" 3) "+new-epoch" 4) "8" 1) "pmessage" 2) "*" 3) "+try-failover" 4) "master master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+vote-for-leader" 4) "691dc32d3a3c1afdc5b18a8e5541c885aa04c487 8" 1) "pmessage" 2) "*" 3) "+elected-leader" 4) "master master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+failover-state-select-slave" 4) "master master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+selected-slave" 4) "slave 192.168.9.10:1112 192.168.9.10 1112 @ master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+failover-state-send-slaveof-noone" 4) "slave 192.168.9.10:1112 192.168.9.10 1112 @ master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+failover-state-wait-promotion" 4) "slave 192.168.9.10:1112 192.168.9.10 1112 @ master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "-role-change" 4) "slave 192.168.9.10:1112 192.168.9.10 1112 @ master-1111 192.168.9.10 1111 new reported role is master" 1) "pmessage" 2) "*" 3) "+promoted-slave" 4) "slave 192.168.9.10:1112 192.168.9.10 1112 @ master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+failover-state-reconf-slaves" 4) "master master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+slave-reconf-sent" 4) "slave 192.168.9.70:2222 192.168.9.70 2222 @ master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+slave-reconf-inprog" 4) "slave 192.168.9.70:2222 192.168.9.70 2222 @ master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+slave-reconf-done" 4) "slave 192.168.9.70:2222 192.168.9.70 2222 @ master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+slave-reconf-sent" 4) "slave 192.168.9.70:2223 192.168.9.70 2223 @ master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+slave-reconf-inprog" 4) "slave 192.168.9.70:2223 192.168.9.70 2223 @ master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+slave-reconf-done" 4) "slave 192.168.9.70:2223 192.168.9.70 2223 @ master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+failover-end" 4) "master master-1111 192.168.9.10 1111" 1) "pmessage" 2) "*" 3) "+switch-master" 4) "master-1111 192.168.9.10 1111 192.168.9.10 1112" 1) "pmessage" 2) "*" 3) "+slave" 4) "slave 192.168.9.70:2222 192.168.9.70 2222 @ master-1111 192.168.9.10 1112" 1) "pmessage" 2) "*" 3) "+slave" 4) "slave 192.168.9.70:2223 192.168.9.70 2223 @ master-1111 192.168.9.10 1112" 1) "pmessage" 2) "*" 3) "+slave" 4) "slave 192.168.9.10:1111 192.168.9.10 1111 @ master-1111 192.168.9.10 1112" 1) "pmessage" 2) "*" 3) "-role-change" 4) "slave 192.168.9.10:1111 192.168.9.10 1111 @ master-1111 192.168.9.10 1112 new reported role is master" 1) "pmessage" 2) "*" 3) "+role-change" 4) "slave 192.168.9.10:1111 192.168.9.10 1111 @ master-1111 192.168.9.10 1112 new reported role is slave"
一次故障轉移操作由以下步驟組成:
(1). 由sentinel主動發起failover或者發現主服務器已經進入客觀下線狀態.
(2). sentinel對我們的當前紀元(epoch)進行自增,並嘗試在這個紀元中當選爲此次failover的總指揮.
(3). 如果當選失敗, 那麼在設定的故障遷移超時時間的兩倍之後, 重新嘗試當選. 如果當選成功, 那麼執行以下步驟.
(4). 選出一個從redis實例,並將它升級爲主redis實例.
(5). 向被選中的從redis實例發送 SLAVEOF NO ONE 命令,讓它轉變爲主redis實例.
(6). 通過發佈與訂閱功能, 將更新後的配置傳播給所有其他 Sentinel , 其他 Sentinel 對它們自己的配置進行更新.
(7). 向已下線主服務器的從服務器發送SLAVEOF命令, 讓它們去複製新的主服務器.
(8). 當所有從redis實例都已經開始複製新的主redis實例時, 領頭Sentinel 終止這次故障遷移操作.
FAQ:
若master實例故障,則最好等sentinel選出new master且穩定後(選新主並完成切換的時間與配置有關,典型值在1分鐘之內),再重啓old master,避免引發sentinel的誤判,導致整個系統無法選出new master.
最大內存問題:要設置好最大內存,以防不停的申請內存,造成系統內存都被用完.
Fork進程問題:’vm.overcommit_memory = 1’這一個選項要加到系統的配置中,防止fork因內存不足而失敗.
密碼問題:需要設置複雜一些,防止暴力破解.
License:Attribution-NonCommercial-NoDerivatives 4.0 International
本文出自 Suzf Blog。 如未註明,均爲 SUZF.NET 原創。
轉載請註明出處:http://suzf.net/thread-0317-627.html