1. 程式人生 > >Redis 高可用叢集管理工具Sentinel

Redis 高可用叢集管理工具Sentinel

Sentinel是一個管理redis例項的工具,它可以實現對redis的監控、通知、自動故障轉移。sentinel不斷的檢測redis例項是否可以正常工作,通過API向其他程式報告redis的狀態,如果redis master不能工作,則會自動啟動故障轉移程序,將其中的一個slave提升為master,其他的slave重新設定新的master伺服器。
Sentinel主要功能有:
1.監控(Monitoring): Redis Sentinel實時監控主伺服器和從伺服器執行狀態。
2.提醒(Notification):當被監控的某個 Redis 伺服器出現問題時, Redis Sentinel 可以向系統管理員傳送通知, 也可以通過 API 向其他程式傳送通知。
3.自動故障轉移
(Automatic failover): 當一個主伺服器不能正常工作時, Sentinel 會開始一次自動故障遷移操作,它會將失效主伺服器的其中一個從伺服器升級為新的主伺服器,並讓失效主伺服器的其他從伺服器改為複製新的主伺服器; 當客戶端試圖連線失效的主伺服器時, 叢集也會向客戶端返回新主伺服器的地址, 使得叢集可以使用新主伺服器代替失效伺服器。
Redis Sentinel 是一個分散式系統, 你可以在一個架構中執行多個 Sentinel 程序(progress), 這些程序使用流言協議(gossip protocols)來接收關於主伺服器是否下線的資訊, 並使用投票協議(agreement protocols)來決定是否執行自動故障遷移, 以及選擇哪個從伺服器作為新的主伺服器。通過Redis Sentinel可以實現Redis零手工干預並且短時間內進行M-S切換,減少業務影響時間。
官網:
http://redis.io/topics/sentinel

中文文件:http://redis.readthedocs.org/en/latest/topic/sentinel.html
一、常用拓撲結構

在兩個伺服器中分別都部署Redis和Redis Sentinel。當Master中的Redis出現故障時(Redis程序終止、伺服器僵死、伺服器斷電等),由Redis Sentinel將Master許可權切換至Slave Redis中,並將只讀模式更改為可讀可寫模式。應用程式通過Redis Sentinal確定當前Master Redis位置,進行重新連線。根據業務模式,可以制定兩種拓撲結構:單M-S結構和雙M-S結構。如果有足夠多的伺服器,可以配置多M-S結構。

1.單M-S結構

單M-S結構特點是在Master伺服器中配置Master Redis(Redis-1M)和Master Sentinel(Sentinel-1M)。Slave伺服器中配置Slave Redis(Redis-1S)和Slave Sentinel(Sentinel-1S)。其中 Master Redis可以提供讀寫服務,但是Slave Redis只能提供只讀服務。因此,在業務壓力比較大的情況下,可以選擇將只讀業務放在Slave Redis中進行。


2.雙M-S結構

雙M-S結構的特點是在每臺伺服器上配置一個Master Redis,同時部署一個Slave Redis。由兩個Redis Sentinel同時對4個Redis進行監控。兩個Master Redis可以同時對應用程式提供讀寫服務,即便其中一個伺服器出現故障,另一個伺服器也可以同時執行兩個Master Redis提供讀寫服務。缺點是兩個Master redis之間無法實現資料共享,不適合存在大量使用者資料關聯的應用使用。


以上2個結構各有優缺點,分別適用於不同的應用場景:
單M-S結構適用於不同使用者資料存在關聯,但應用可以實現讀寫分離的業務模式。Master主要提供寫操作,Slave主要提供讀操作,充分利用硬體資源。雙(多)M-S結構適用於使用者間不存在或者存在較少的資料關聯的業務模式,讀寫效率是單M-S的兩(多)倍,但要求故障時單臺伺服器能夠承擔兩個Mater Redis的資源需求。
二、叢集部署
單M-S結構和雙M-S結構配置相差無幾,下面以雙M-S結構配置為例,並使用客戶端工具實現分片。

1.架構圖


環境如下:

sentinel 節點:
192.168.100.90 6000  sentinel節點
192.168.110.71 6000  sentinel節點
shard_a:
192.168.100.90 6379  redis主
192.168.110.71 6379  redis備
shard_b:
192.168.110.71 6380  redis主
192.168.100.90 6380  redis備
2.部署
daemonize  yes  
pidfile /home/slim/redis/data/redis_6379.pid  
port 6379  
bind 192.168.100.90
unixsocket /home/slim/redis/data/redis_6379.sock  
timeout 300  
loglevel verbose  
logfile /home/slim/redis/logs/redis_6379.log  
databases 16  
dbfilename dump_6379.rdb  
dir /home/slim/redis/data/
redis備:
daemonize  yes  
pidfile /home/slim/redis/data/redis_6379.pid  
port 6379  
bind 192.168.110.71
unixsocket /home/slim/redis/data/redis_6379.sock  
timeout 300  
loglevel verbose  
logfile /home/slim/redis/logs/redis_6379.log  
databases 16  
dbfilename dump_6379.rdb  
dir /home/slim/redis/data/
slaveof 192.168.100.90 6379
2)配置sentinel
複製一份預設配置檔案,(兩臺機器相同操作)
cp /home/slim/redis-2.8.19/sentinel.conf ./conf/
mkdir tmp
vi conf/sentinel.conf
port 6000
daemonize yes
logfile  /home/slim/redis/logs/sentinel.log
dir /home/slim/redis/tmp
sentinel monitor shard_a 192.168.100.90 6379 1
sentinel down-after-milliseconds shard_a 30000
sentinel parallel-syncs shard_a 1
sentinel failover-timeout shard_a 180000

sentinel monitor shard_b 192.168.110.71 6380 1
sentinel down-after-milliseconds shard_b 30000
sentinel parallel-syncs shard_b 1
sentinel failover-timeout shard_b 180000
3.啟動服務
1)啟動兩臺機器主從redis服務
./bin/redis-server ./conf/redis-6379.conf;tail -f logs/redis_6379.log
./bin/redis-server ./conf/redis-6380.conf;tail -f logs/redis_6380.log
檢視主從狀態:

./bin/redis-cli -h 192.168.100.90 -p 6379 info Replication

# Replication
role:master
connected_slaves:1
slave0:ip=192.168.110.71,port=6379,state=online,offset=50748,lag=1
master_repl_offset:50748
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:50747
./bin/redis-cli -h 192.168.110.71 -p 6380 info Replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.100.90,port=6380,state=online,offset=58630,lag=0
master_repl_offset:58630
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:58629
2)啟動兩臺機器sentinel服務
./bin/redis-sentinel ./conf/sentinel.conf;tail -f logs/sentinel.log
也可以使用如下命令啟動:
./bin/redis-server  --sentinel ./conf/sentinel.conf;tail -f logs/sentinel.log
啟動日誌:
[18871] 10 Apr 13:28:21.542 # Sentinel runid is 11b2696c7f6911bf9fa347c8e670571a63be0002
[18871] 10 Apr 13:28:21.542 # +monitor master shard_a 192.168.100.90 6379 quorum 1
[18871] 10 Apr 13:28:21.542 # +monitor master shard_b 192.168.110.71 6380 quorum 1
[18871] 10 Apr 13:28:21.543 * +slave slave 192.168.110.71:6379 192.168.110.71 6379 @ shard_a 192.168.100.90 6379
[18871] 10 Apr 13:28:21.545 * +slave slave 192.168.100.90:6380 192.168.100.90 6380 @ shard_b 192.168.110.71 6380
[18871] 10 Apr 13:28:49.589 * +sentinel sentinel 192.168.110.71:6000 192.168.110.71 6000 @ shard_b 192.168.110.71 6380
[18871] 10 Apr 13:28:49.624 * +sentinel sentinel 192.168.110.71:6000 192.168.110.71 6000 @ shard_a 192.168.100.90 6379
檢視master狀態
./bin/redis-cli -h 192.168.110.71 -p 6000  info Sentinel
# Sentinel
sentinel_masters:2
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
master0:name=shard_b,status=ok,address=192.168.110.71:6380,slaves=1,sentinels=2
master1:name=shard_a,status=ok,address=192.168.100.90:6379,slaves=1,sentinels=2
查詢slave狀態

./bin/redis-cli -h 192.168.110.71 -p 6000 sentinel slaves shard_a

1)  1) "name"
    2) "192.168.110.71:6379"
    3) "ip"
    4) "192.168.110.71"
    5) "port"
    6) "6379"
    7) "runid"
    8) "629e59944e4da9af14477737da9e959751549177"
    9) "flags"
   10) "slave"
   11) "pending-commands"
   12) "0"
   13) "last-ping-sent"
   14) "0"
   15) "last-ok-ping-reply"
   16) "91"
   17) "last-ping-reply"
   18) "91"
   19) "down-after-milliseconds"
   20) "30000"
   21) "info-refresh"
   22) "8621"
   23) "role-reported"
   24) "slave"
   25) "role-reported-time"
   26) "560540"
   27) "master-link-down-time"
   28) "0"
   29) "master-link-status"
   30) "ok"
   31) "master-host"
   32) "192.168.100.90"
   33) "master-port"
   34) "6379"
   35) "slave-priority"
   36) "100"
   37) "slave-repl-offset"
   38) "80652"
返回資料中顯示了幾個從庫(name數量),從庫的IP地址和狀態,主庫的IP地址和狀態。還有‘runid’ ,redis的從接管主沒有優先順序的引數可以配置,預設使用runid的大小來競爭主庫,所以這裡也可以預測下一個主是哪臺。

需要注意的幾個地方
1)sentinel配置中sentinel monitor最後的數字1,意思是當有1個sentinel例項同時檢測到redis異常時,才會有反應。
2)主從切換後,redis.conf、sentinel.conf內容都會改變,主要還想要原來的主從架構,要再修改配置檔案;
3)master掛掉,sentinel已經選擇了新的master,但是還沒有將其改成master,但是已經將old master改成了slave。那麼這時候如果重啟old master,就會處於無主狀態。所以一方面要等sentinel穩定後再啟動old master,或者重新人工修改配置檔案,重新啟動叢集。
4)sentinel只是在server端做主從切換,app端要自己開發,例如Jedis庫的SentinelJedis,能夠監控sentinel的狀態。這樣才能完整的實現高可用性的主從切換。
三、測試
1.我們將shard_a中的主伺服器(192.168.100.90:6379)關閉掉,檢視一下故障轉移情況
ps -ef | grep redis
slim     18514     1  0 13:20 ?        00:00:00 ./bin/redis-server 192.168.100.90:6379   
slim     18635     1  0 13:22 ?        00:00:00 ./bin/redis-server 192.168.100.90:6380   
slim     18871     1  0 13:28 ?        00:00:00 ./bin/redis-sentinel *:6000  
kill -2 18514
檢視一下shard_a從伺服器日誌

[23815] 10 Apr 14:10:01.706 # Error condition on socket for SYNC: Connection refused
[23815] 10 Apr 14:10:02.181 * Discarding previously cached master state.
[23815] 10 Apr 14:10:02.181 * MASTER MODE enabled (user request)
[23815] 10 Apr 14:10:02.184 # CONFIG REWRITE executed with success.
[23815] 10 Apr 14:10:02.204 - Accepted 192.168.100.90:43533
[23815] 10 Apr 14:10:02.209 * 1 changes in 900 seconds. Saving...
[23815] 10 Apr 14:10:02.210 * Background saving started by pid 24343
[24343] 10 Apr 14:10:02.246 * DB saved on disk
[24343] 10 Apr 14:10:02.247 * RDB: 0 MB of memory used by copy-on-write
[23815] 10 Apr 14:10:02.310 * Background saving terminated with success
[23815] 10 Apr 14:10:02.712 - 4 clients connected (0 slaves), 835472 bytes in use
檢視sentinel選舉日誌
[24107] 10 Apr 14:10:01.930 # +sdown master shard_a 192.168.100.90 6379
[24107] 10 Apr 14:10:01.931 # +odown master shard_a 192.168.100.90 6379 #quorum 1/1
[24107] 10 Apr 14:10:01.931 # +new-epoch 1
[24107] 10 Apr 14:10:01.931 # +try-failover master shard_a 192.168.100.90 6379
[24107] 10 Apr 14:10:01.964 # +vote-for-leader 4383f49c49059f2a223e12c428f7eb446667ff61 1
[24107] 10 Apr 14:10:02.005 # 192.168.100.90:6000 voted for 4383f49c49059f2a223e12c428f7eb446667ff61 1
[24107] 10 Apr 14:10:02.018 # +elected-leader master shard_a 192.168.100.90 6379
[24107] 10 Apr 14:10:02.018 # +failover-state-select-slave master shard_a 192.168.100.90 6379
[24107] 10 Apr 14:10:02.080 # +selected-slave slave 192.168.110.71:6379 192.168.110.71 6379 @ shard_a 192.168.100.90 6379
[24107] 10 Apr 14:10:02.080 * +failover-state-send-slaveof-noone slave 192.168.110.71:6379 192.168.110.71 6379 @ shard_a 192.168.100.90 6379
[24107] 10 Apr 14:10:02.181 * +failover-state-wait-promotion slave 192.168.110.71:6379 192.168.110.71 6379 @ shard_a 192.168.100.90 6379
[24107] 10 Apr 14:10:03.048 # +promoted-slave slave 192.168.110.71:6379 192.168.110.71 6379 @ shard_a 192.168.100.90 6379
[24107] 10 Apr 14:10:03.049 # +failover-state-reconf-slaves master shard_a 192.168.100.90 6379
[24107] 10 Apr 14:10:03.087 # +failover-end master shard_a 192.168.100.90 6379
[24107] 10 Apr 14:10:03.087 # +switch-master shard_a 192.168.100.90 6379 192.168.110.71 6379
[24107] 10 Apr 14:10:03.087 * +slave slave 192.168.100.90:6379 192.168.100.90 6379 @ shard_a 192.168.110.71 6379
[24107] 10 Apr 14:10:33.090 # +sdown slave 192.168.100.90:6379 192.168.100.90 6379 @ shard_a 192.168.110.71 6379
檢視master狀態
./bin/redis-cli -h 192.168.110.71 -p 6000  info Sentinel
# Sentinel
sentinel_masters:2
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
master0:name=shard_b,status=ok,address=192.168.110.71:6380,slaves=1,sentinels=2
master1:name=shard_a,status=ok,address=192.168.110.71:6379,slaves=1,sentinels=2
可以看到shard_a主伺服器已經切換到192.168.110.71:6379
2.再啟動192.168.100.90:6379 redis服務
可以看到啟動日誌,192.168.100.90:6379 變成從伺服器。
[20225] 10 Apr 14:15:33.277 * SLAVE OF 192.168.110.71:6379 enabled (user request)
[20225] 10 Apr 14:15:33.278 # CONFIG REWRITE executed with success.
[20225] 10 Apr 14:15:33.278 - Accepted 192.168.100.90:59955
[20225] 10 Apr 14:15:34.249 * Connecting to MASTER 192.168.110.71:6379
[20225] 10 Apr 14:15:34.249 * MASTER <-> SLAVE sync started
[20225] 10 Apr 14:15:34.249 * Non blocking connect for SYNC fired the event.
[20225] 10 Apr 14:15:34.250 * Master replied to PING, replication can continue...
[20225] 10 Apr 14:15:34.250 * Partial resynchronization not possible (no cached master)
[20225] 10 Apr 14:15:34.251 * Full resync from master: 629e59944e4da9af14477737da9e959751549177:1
[20225] 10 Apr 14:15:34.358 * MASTER <-> SLAVE sync: receiving 18 bytes from master
檢視master狀態
./bin/redis-cli -h 192.168.110.71 -p 6000  info Sentinel
# Sentinel
sentinel_masters:2
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
master0:name=shard_b,status=ok,address=192.168.110.71:6380,slaves=1,sentinels=2
master1:name=shard_a,status=ok,address=192.168.110.71:6379,slaves=1,sentinels=2
四、備份恢復
1.備份策略

Redis提供兩種相對有效的備份方法:RDB和AOF。
RDB是在某個時間點將記憶體中的所有資料的快照儲存到磁碟上,在資料恢復時,可以恢復備份時間以前的所有資料,但無法恢復備份時間點後面的資料。
AOF是以協議文字的方式,將所有對資料庫進行過寫入的命令(及其引數)記錄到 AOF 檔案,以此達到記錄資料庫狀態的目的。優點是基本可以實現資料無丟失(快取的資料有可能丟失),缺點是隨著資料量的持續增加,AOF檔案也會越來越大。
在保證資料安全的情況下,儘量避免因備份資料消耗過多的Redis資源,採用如下備份策略:
Master端:不採用任何備份機制
Slave端:採用AOF(嚴格資料要求時可同時開啟RDB),每天將AOF檔案備份至備份伺服器。
為了最大限度減少Master端的資源干擾,將備份相關全部遷移至Slave端完成。同時這樣也有缺點,當Master掛掉後,應用服務切換至Slave端,此時的Slave端的負載將會很大。目前Redis不支援RDB和AOF引數動態修改,需要重啟Redis生效,希望能在新的版本中實現更高效的修改方式。
2.災難恢復
當Master端Redis服務崩潰(包含主機斷電、程序消失等),Redis sentinel將Slave切換為讀寫狀態,提供生產服務。通過故障診斷修復Master,啟動後會自動加入Sentinel並從Slave端完成資料同步,但不會切換。
當Master和Slave同時崩潰(如機房斷電),啟動伺服器後,將備份伺服器最新的AOF備份拷貝至Master端,啟動Master。一切完成後再啟動Slave。

五、sentinel配置說明

##sentinel例項之間的通訊埠
##redis-0
port 6000
##sentinel需要監控的master資訊:<mastername> <masterIP> <masterPort> <quorum>
##sentinel建議部署大於3的奇數n,<quorum>建議為n/2+1,只有當至少<quorum>個sentinel例項提交"master失效"
##才會認為master為O_DWON("客觀"失效)
sentinel monitor def_master 127.0.0.1 6379 2
sentinel auth-pass def_master 012_345^678-90
##master被當前sentinel例項認定為“失效”的間隔時間
##如果當前sentinel與master直接的通訊中,在指定時間內沒有響應或者響應錯誤程式碼,那麼
##當前sentinel就認為master失效(SDOWN,“主觀”失效)
##<mastername> <millseconds>
##預設為30秒
sentinel down-after-milliseconds def_master 30000

##當前sentinel例項是否允許實施“failover”(故障轉移)
##no表示當前sentinel為“觀察者”(只參與"投票".不參與實施failover),
##全域性中至少有一個為yes
sentinel can-failover def_master yes

##當新master產生時,同時進行“slaveof”到新master並進行“SYNC”的slave個數。
##預設為1,建議保持預設值
##在salve執行salveof與同步時,將會終止客戶端請求。
##此值較大,意味著“叢集”終止客戶端請求的時間總和和較大。
##此值較小,意味著“叢集”在故障轉移期間,多個salve向客戶端提供服務時仍然使用舊資料。
sentinel parallel-syncs def_master 1

##failover過期時間,當failover開始後,在此時間內仍然沒有觸發任何failover操作,
##當前sentinel將會認為此次failoer失敗。
sentinel failover-timeout def_master 900000

##當failover時,可以指定一個“通知”指令碼用來告知系統管理員,當前叢集的情況。
##指令碼被允許執行的最大時間為60秒,如果超時,指令碼將會被終止(KILL)
##指令碼執行的結果:
## 1	-> 稍後重試,最大重試次數為10; 
## 2	-> 執行結束,無需重試
##sentinel notification-script mymaster /var/redis/notify.sh

##failover之後重配置客戶端,執行指令碼時會傳遞大量引數,請參考相關文件
# sentinel client-reconfig-script <master-name> <script-path>

針對Sentinel叢集客戶端如何使用,下一節我們以java客戶端為例,講解其使用。

8.Redis Sentinel機制與用法

https://segmentfault.com/a/1190000002680804