title: redis哨兵模式
date: 2021-01-12 21:22:54
categories: redis
tags:
- sentinel
description: 哨兵模式是一種常見的高可用架構(gòu)
基本概念
使用主從復制能夠?qū)⒅鞴?jié)點的數(shù)據(jù)同步到從節(jié)點,一定程度上保證了數(shù)據(jù)的完整性,也提供了擴展讀的能力。
但是主從復制有以下問題:
- 一旦主節(jié)點宕機,需要手動提升從節(jié)點為主節(jié)點
- 主節(jié)點的寫能力受到單機的限制
- 主節(jié)點的存儲能力也受到單機的限制
高可用
Redis主從模式下一定程度上解決了高可用問題,但是全程需要人去干預,非常不方便,考慮到這點,有些公司把一些
流程自動化,但是會存在一些問題,比如判斷節(jié)點不可用的機制是否完善、如何從多個從節(jié)點中選出一個晉升為主節(jié)點等等,
Redis Sentinel方案正式用于解決這些問題。
當主節(jié)點出現(xiàn)故障時,Redis Sentinel能夠自動完成故障發(fā)現(xiàn)和故障轉(zhuǎn)移,并通知應用方,實現(xiàn)真正的高可用。
Redis Sentinel是一個分布式架構(gòu),其中包含多個Sentinel節(jié)點和數(shù)據(jù)節(jié)點,每個Sentinel節(jié)點都會實時監(jiān)控數(shù)據(jù)節(jié)點和
其他sentinel節(jié)點,并維護它們,整個過程都是自動完成的。
整個過程如下:
- Sentinel發(fā)現(xiàn)主節(jié)點出現(xiàn)故障
- 多個Sentinel節(jié)點對主節(jié)點的故障達成一致,選舉出某個sentinel節(jié)點作為leader負責故障轉(zhuǎn)移
- leader完成故障轉(zhuǎn)移
- 1)提升從節(jié)點
- 2)設(shè)置之前的從節(jié)點設(shè)置新的主節(jié)點
- 3)通知客戶端
- 4)等之前的主節(jié)點恢復后,設(shè)置為從節(jié)點
安裝和部署
-
部署主從節(jié)點
redis-server redis-6379.conf主節(jié)點redis-server redis-6378.conf # 從節(jié)點1 slaveof 127.0.0.1 6379 redis-server redis-6380.conf #從節(jié)點2 slaveof 127.0.0.1 6379 -
部署Sentinel節(jié)點
sentinel-26379.conf port 26379 sentinel monitor mymaster 127.0.0.1 6379 2 -
啟動Sentinel節(jié)點
兩種方式:- 一種是使用redis-server:
redis-server sentinel-26379.conf --sentinel - 另一種是使用redis-sentinel:
redis-sentinel sentinel-26379.conf
- 一種是使用redis-server:
-
檢查
127.0.0.1:26379> info sentinel # Sentinel sentinel_masters:1 sentinel_tilt:0 sentinel_running_scripts:0 sentinel_scripts_queue_length:0 sentinel_simulate_failure_flags:0 master0:name=mymaster,status=ok,address=100.101.71.99:6379,slaves=2,sentinels=3 -
重要配置選項
- sentinel monitor {master-name} {ip} {port} {quorum}
sentinel節(jié)點會定期監(jiān)控主節(jié)點,quorum代表判定主節(jié)點不可用需要的票數(shù),這里只配置了一個ip,是因為,sentinel節(jié)點會自動從主節(jié)點中獲取其他從節(jié)點信息。 - sentinel down-after-milliseconds
每個sentinel節(jié)點要定期ping命令來判斷數(shù)據(jù)節(jié)點和哨兵節(jié)點是否可達,超過了這個值,就表示不可達。 - sentinelparallel-syns
這個值表示在故障轉(zhuǎn)移確定了新的主節(jié)點后,每次向新的主節(jié)點發(fā)起復制操作的從節(jié)點個數(shù),如果過大,則可能在故障轉(zhuǎn)移時發(fā)生阻塞 - sentinel failover-timeout
故障轉(zhuǎn)移的超時時間 - sentinel notification-script
在故障轉(zhuǎn)移期間,當一些警告級別的sentinel事件發(fā)生的時候會觸發(fā)腳本
- sentinel monitor {master-name} {ip} {port} {quorum}
哨兵模式下特殊API
- sentinel master 展示主節(jié)點狀態(tài)及其統(tǒng)計信息
- sentinel slaves {master name} 展示從節(jié)點信息
- sentinel reset {pattern} 對符合pattern的主節(jié)點的配置進行重置
- sentinel failover{mastername} 對指定主節(jié)點進行強制故障轉(zhuǎn)移
- sentinel flushconfig,將哨兵節(jié)點的配置刷新到磁盤上,對于磁盤配置文件損壞的情況很有用
- sentinel remove {master-name} 取消該哨兵對于master節(jié)點的監(jiān)控
- sentinel monitor {master-name} {ip}相反的命令
- sentinel set 動態(tài)設(shè)置相關(guān)配置
實現(xiàn)原理
三個定時任務
Redis Sentinel 通過三個定時監(jiān)控任務完成對各個節(jié)點的發(fā)現(xiàn)與監(jiān)控
-
每隔10秒,每個Sentinel 節(jié)點會向主節(jié)點和從節(jié)點發(fā)送info命令獲取最新的拓撲結(jié)構(gòu)
$> info replication role:master connected_slaves:2 slave1:ip=127.0.0.1,port=6380,state=online,mymaster,offset=0,lag=0 slave2:ip=127.0.0.1,port=6381,state=online,mymaster,offset=0,lag=0該定時任務的作用:
- 通過主節(jié)點執(zhí)行info,獲取從節(jié)點的信息,所以無需顯式配置監(jiān)控從節(jié)點
- 當有新的從節(jié)點加入,能夠及時感知到
- 節(jié)點不可達或者故障轉(zhuǎn)移后,能及時更新拓撲結(jié)構(gòu)
-
每隔2秒,都會向Redis數(shù)據(jù)節(jié)點的sentinel:hello頻道上發(fā)送該Sentinel節(jié)點對于主節(jié)點的判斷以及當前sentinel節(jié)點的信息
同時sentinel節(jié)點也會訂閱該頻道,互相交換主節(jié)點狀態(tài),以及版本信息$:SUBSCRIBE __sentinel__:hello 1) "message" 2) "__sentinel__:hello" 3) "100.101.71.99,26380,13da260e2869a5758a089a2e6fdf50a2e2c23d6e,1,mymaster,100.101.71.99,6380,1該定時任務的作用:
- 發(fā)現(xiàn)新的sentinel節(jié)點
- 更新配置,如果發(fā)現(xiàn)自己的版本低于其他節(jié)點的版本,則會更新,有點類似zookeeper的主節(jié)點選舉,都用到了epoch
每隔1秒每個Sentinel節(jié)點會向主節(jié)點、從節(jié)點、其余Sentinel節(jié)點發(fā)送一條ping命令做一次心跳檢測
該定時任務的作用是判斷節(jié)點是否健康的重要依據(jù),也就是ping之后,如果失敗則主觀下線
主觀下線和客觀下線
- 主觀下線
每隔1秒ping命令做心跳檢測時,如果沒有在down-after-milliseconds時間內(nèi)有效回復,則會判定該節(jié)點失敗。 - 客觀下線
當Sentinel節(jié)點主觀下線的節(jié)點是master節(jié)點時,該Sentinel節(jié)點會通過Sentinel is-master-down-by-addr命令向其他Sentinel節(jié)點詢問對主節(jié)點的判斷,
當超過quorum個達成一致時,則會主觀下線master節(jié)點
Sentinel領(lǐng)導者選舉
當Sentinel節(jié)點對于master節(jié)點做了客觀下線后,需要確定哨兵節(jié)點的leader,因為故障轉(zhuǎn)移只需要一個Sentinel節(jié)點來完成。
選舉的過程相對比較簡單:
- 每個Sentinel節(jié)點只有一票
- 每個在線的Sentinel節(jié)點都有可能成為leader,當它確認master主觀下線時,會想起他Sentinel節(jié)點發(fā)送成為leader的請求
- 收到命令的Sentinel節(jié)點,如果沒有投過票,則會同意該請求,也就是投票
- 如果該Sentinel節(jié)點發(fā)現(xiàn)自己的票數(shù)大于等于max(quorum,num(sentinels)/2+1),則會成為leader
基于此原則,可以判斷誰最先向各個節(jié)點發(fā)出請求,則最有可能會成為leader
故障轉(zhuǎn)移
- 從follower節(jié)點中選出一個可用節(jié)點(存活、優(yōu)先級最高、復制偏移量最大、runid最小(優(yōu)先級依次降低)的從節(jié)點)
- 對從節(jié)點執(zhí)行slaveof no one
- Sentinel節(jié)點向其他從節(jié)點發(fā)送命令,讓它們復制新的主節(jié)點
- Sentinel節(jié)點集合將原來的master節(jié)點更新為從節(jié)點
運維提示
- 主要分析日志,整個過程都有日志打印
- 需要對主節(jié)點下線時,比較合理的做法是使用sentinel failover命令,主動進行故障轉(zhuǎn)移。
- 如果想指定某個slave節(jié)點成為master節(jié)點,則可以設(shè)置其他節(jié)點的優(yōu)先級slave-priority為0,再執(zhí)行sentinel failover命令,最后將優(yōu)先級調(diào)回來。
config get slave-priority
網(wǎng)絡(luò)隔離的一致性
如果某個節(jié)點上sentinel和redis實例在同一個網(wǎng)絡(luò),其他的在另一個網(wǎng)絡(luò),當發(fā)送網(wǎng)絡(luò)中斷時會發(fā)生意外:
+-------------+
| Sentinel 1 | <--- Client A
| Redis 1 (M) |
+-------------+
|
|
+-------------+ | +------------+
| Sentinel 2 |-----+-- / partition / ----| Sentinel 3 | <--- Client B
| Redis 2 (S) | | Redis 3 (M)|
+-------------+ +------------+
Redis3一開始是master,網(wǎng)絡(luò)斷開后,Redis1成為了新的主節(jié)點,Sentinel1和Sentinel2更新了配置,但這是Sentinel3還是原來的配置,這個時候我們出現(xiàn)了常說的腦裂現(xiàn)象(分布式常見的問題),ClientB仍然向Redis3寫數(shù)據(jù)。
當網(wǎng)絡(luò)恢復后,Sentinel3恢復更新配置,這時Redis3成為了slave,之前ClientB寫入的數(shù)據(jù)將會丟失。
如果把redis當成緩存,也許可以容忍,但如果是一個存儲系統(tǒng),則無法容忍。
如果看過zookeeper的源碼分析就知道,zookeeper有機制防止腦裂現(xiàn)象,它是通過持續(xù)交換信息,大于一般才正常工作,但這里的redis不是,為什么redis像zookeeper那樣,保證
節(jié)點只有在超過半數(shù)以上才可用呢?我個人感覺根據(jù)cpa和base理論,Redis為了保證可用性,使用的是最終一致性,犧牲了高度一致性,尤其是其異步機制,也就是PA+最終一致性。另外在網(wǎng)絡(luò)發(fā)生分區(qū)時A和P基本不可實現(xiàn)。也就是說當網(wǎng)絡(luò)分區(qū)發(fā)生時只有PA和PC,由于被斷開網(wǎng)絡(luò)的那小部分不可用(如下文所說的配置)又在一定程度上變成了PC。
另外在分布式系統(tǒng)中,只要是不是在一個節(jié)點上部署,那么分區(qū)的情況將不可避免,所以如果滿足CA,當數(shù)據(jù)分區(qū)時則最終會退化為只有A或者C,所以系統(tǒng)一般做成PA或者PC,而不是CA。
解決方法:
保證主節(jié)點至少有一個slave節(jié)點,但因為復制過程是異步的,所以需要兩個配置:
min-replicas-to-write 1
min-replicas-max-lag 10
min-replicas-to-write保證了至少一個slave節(jié)點
min-replicas-max-lag,保證了slave節(jié)點復制同步最多10秒的延遲,如果10秒內(nèi)沒有同步成功,則代表slave失敗。
但還是有10秒的數(shù)據(jù)丟失