進階的Redis之Sentinel原理及實戰
Redis作為一款高效的記憶體資料庫,可作用於方方面面,相信如今專案的開發都離不開它。大家可能都知道Redis是高可用的,但很少知道具體高可用是利用什麼去實現的。
拋兩個問題:
- 只部署一個Redis例項,如果這個例項掛了就無法讀寫資料了,那怎麼做例項備份?
- 部署了兩個Redis,一主一從做複製,從只讀,如果主掛了,那這個服務還怎麼正常對外服務?
顯然,要做到高可用,首先要有足夠多的Redis例項(最好三臺以上),一主多從。然後再主掛了的時候,要有機制讓其他例項替代主的位置。
哨兵服務Sentinel,就是這套題的答案,它是一個檢查redis服務下線並補償的服務。下面我們來完整了解下Sentinel的作用和工作原理,最後實驗下它的效果。
Sentinel簡介
直接看下最新版的官方的介紹

大致意思是,Sentinel為Redis提供高可用。利用Sentinel,在無人干預的情況下,可用讓Redis服務抵禦一定程度的故障。
巨集觀層面,Sentinel擁有以下幾個功能:
- 監控(Monitoring),Sentinel可用持續不斷地檢查主從例項是否如期執行。
- 通知(Notification),當某個被監控的Redis例項出問題的時候,可以通過API介面向系統管理員和其他應用服務發通知。
- 自動故障轉移(Automatic failover),當主出現故障時,Sentinel會自動啟動故障轉移流程,把其中一個從庫提升為主庫,然後其他從庫重新認新主。叢集也會返回新的地址給客戶端。
- 配置提供(Configuration provider),Sentinel可以作為服務註冊中心,讓客戶端直接連線請求Sentinel去獲取主庫的地址。如果出現自動故障轉移,Sentinel也會提供新的主庫地址。

P.S. 文中所描述的庫和伺服器都是指Redis的server例項。
高可用工作原理
下面我們以Sentinel的故障轉移為核心,來看看它具體是怎麼實現Sentinel的。
- 啟動並初始化Sentinel
執行redis-sentinel /usr/local/etc/redis-sentinel.conf
Sentinel是Redis的特殊模式,執行redis-server /usr/local/etc/redis-sentinel.conf --sentinel
命令也是完全一樣的。其實在啟動Sentinel的時候,redis只是把執行程式碼切換到sentinel模式。 Sentinel模式下,具體的功能如圖, - 初始化master屬性
配置檔案中是需要指定了監控的主庫,然後再初始化階段把Sentinel例項中的master屬性初始化。 - Sentinel向主庫建立網路連線
在master屬性初始化後,Sentinel首先就需要和該主庫建立網路連線。Sentinel會對每個被監視的主庫建立兩個連結。一個命令連結,用於給主庫傳送操作命令的。另一個是訂閱連結,訂閱主庫的_ sentinel _:hello頻道,主要用於發現其他Sentinel的存在(後面會說到)。 - 獲取主庫資訊
Sentinel預設以十秒一次,通過命令連結,給主庫傳送INFO命令,來獲取主庫的當前資訊。資訊包括該主庫的執行id以及該主庫下所有從庫的ip埠。 - 根據主庫資訊,獲取從庫資訊
如果Sentinel在獲取主庫資訊時候,發現有新未連結的從庫,會與該從庫同樣建立兩條連結。建立連結後,Sentinel同樣會給從庫通過命令連結傳送INFO命令,從而獲取該從庫的伺服器資訊。 - 向主和從傳送伺服器訊息
Sentinel預設以兩秒一次,通過命令連結,對_ sentinel _:hello頻道傳送Sentinel自身資訊與被監控的主庫資訊。該頻道是之前Sentinel與所有主從庫都建立的頻道連結。所以被監視的主從庫都會收到傳送訊息的Sentinel資訊與主庫資訊。 - 接收主從頻道訊息,找出其他Sentinel
因為Sentinel訂閱了_ sentinel _:hello的訊息,所以在之前向主從庫傳送訊息的時候,同時會通過訂閱連結收到訂閱的內容。這個作用在於,部署多個Sentinel時,其他Sentinel就會知道傳送訊息的那個Sentinel的存在。 - 與其他Sentinel建立連線
當Sentinel發現有其他Sentinel存在的時候,就會與其他Sentinel建立一條命令連結,用於在後續情況傳送命令。但Sentinel之間不會建立訂閱連結,因為訂閱連結是用於發現其他Sentinel的存在的。 - 主觀下線
Sentinel預設以一秒一次,通過命令連結,對所有伺服器(包括主從、其他Sentinel)傳送PING命令來檢測服務是否線上。如果一個服務在引數down-after-millisecond
內連續返回無效回覆,那麼Sentinel會對該服務標記為主觀下線狀態。所謂的主觀下線,就是Sentinel自己認為該服務下線了。 - 主庫客觀下線
當Sentinel將一個主庫主觀下線後,為了判斷是否其他Sentinel都認為該主庫下線了,會通過is-master-down-by-addr
命令詢問。當認為下線的Sentinel資料大於配置中的quorum數時,Sentinel會標記該主庫為客觀下線。 - 選舉Sentinel leader
當Sentinel將主庫客觀下線後,會與其他Sentinel進行協商,選舉出一個leader來執行後續的Failover(故障轉移)。 - 選出新主庫
leader按從庫優先順序配置、複製偏移量、執行id來選舉出新的主庫。leader會向挑選出來的從庫傳送SLAVEOF no one命令,將從庫提升為master角色,成為主庫。 - 讓從庫複製新主庫
在選出新主庫後,就是讓原來的從庫去複製新主庫。leader Sentinel通過給剩餘舊從庫傳送SLAVEOF命令即可。 - 舊主庫變為新主庫的從庫
當原來故障的主庫再次上線的時候,Sentinel會發送SLAVEOF命令,讓其成為新主庫的從庫。
實驗實戰
- 啟動三個Redis例項
redis-server --port 6379 & redis-server --port 6380 & redis-server --port 6381 & 複製程式碼
注意最好各個例項的priority不同,用於故障轉移選主。否則可能會找不到新主。 2. 把80與81的例項作為79的從伺服器 在80與81上執行
SLAVEOF 127.0.0.1 6379 複製程式碼
- 啟動sentinel
redis-sentinel /usr/local/etc/redis-sentinel.conf 複製程式碼
其中的Sentinel配置包含
sentinel monitor mymaster 127.0.0.1 6379 1 複製程式碼
可以觀察到sentinel已經添加了一主兩從的監控。

4. 把主庫的例項關掉
127.0.0.1:6379> SHUTDOWN 複製程式碼
- 故障轉移 redis-cli連上sentinel可以看到,當sentinel檢測到主庫下線,後面根據一些列操作把81替換為主庫,其他庫為81的從庫,並且79是下線的新從庫。
更多技術文章、精彩乾貨,請關注
部落格:zackku.com
微信公眾號:Zack說碼
