1. 程式人生 > >Redis高可用sentinel

Redis高可用sentinel

1.sentine介紹

Redis-Sentinel是Redis官方推薦的高可用性(HA)解決方案,當用Redis做Master-slave的高可用方案時,假如master宕機了,Redis本身(包括它的很多客戶端)都沒有實現自動進行主備切換,而Redis-sentinel本身也是一個獨立執行的程序,它能監控多個master-slave叢集,發現master宕機後能進行自動切換。

sentinel的構造

Sentinel 是一個監視器,它可以根據被監視例項的身份和狀態來判斷應該執行何種動作。

sentinel的功能

1)監控(Monitoring):
Sentinel會不斷地檢查你的主伺服器和從伺服器是否運作正常。

2)提醒(Notification):
當被監控的某個Redis伺服器出現問題時,Sentinel可以通過API向管理員或者其他應用程式傳送通知。

3)自動故障遷移(Automatic failover):
當一個主伺服器不能正常工作時,Sentinel會開始一次自動故障遷移操作,它會將失效主伺服器的其中一個從伺服器升級為新的主伺服器,並讓失效主伺服器的其他從伺服器改為複製新的主伺服器;當客戶端試圖連線失效的主伺服器時,叢集也會向客戶端返回新主伺服器的地址,使得叢集可以使用新主伺服器代替失效伺服器。

發現並連線主伺服器

Sentinel通過使用者給定的配置檔案來發現主伺服器。

Sentinel會與被監視的主伺服器建立兩個網路連線:
命令連線

用於向主伺服器傳送命令。
訂閱連線用於訂閱指定的頻道,從而發現監視同一主伺服器的其他Sentinel。

配置檔案示例

redis-sentinel sentinel.conf


############ master1 configure ##############
sentinel monitor master1 127.0.0.1 6379 2
sentinel down-after-milliseconds master1 30000
sentinel parallel-syncs master1 1
sentinel failover-timeout master1 900000


############ master2 configure ##############
sentinel monitor master2 127.0.0.1 12345 5
sentinel down-after-milliseconds master2 50000
sentinel parallel-syncs master2 5
sentinel failover-timeout master2 450000

發現並連線從伺服器

Sentinel通過向主伺服器傳送INFO命令來自動獲得所有從伺服器的地址

跟主伺服器一樣,Sentinel 會與每個被發現的從伺服器建立命令連線和訂閱連線。

發現其他sentinel

Sentinel 會通過命令連線向被監視的主從伺服器傳送 “HELLO” 資訊,該訊息包含 Sentinel 的 IP、埠號、ID 等內容,以此來向其他 Sentinel 宣告自己的存在。與此同時Sentinel 會通過訂閱連線接收其他 Sentinel 的“HELLO” 資訊,以此來發現監視同一個主伺服器的其他 Sentinel 。

1)一個Sentinel可以與其他多個Sentinel進行連線,各個Sentinel之間可以互相檢查對方的可用性,並進行資訊交換。你無須為執行的每個 Sentinel 分別設定其他 Sentinel 的地址,因為Sentinel可以通過釋出與訂閱功能來自動發現正在監視相同主伺服器的其他 Sentinel ,這一功能是通過向頻道__sentinel__:hello傳送資訊來實現的。

2)與此類似,你也不必手動列出主伺服器屬下的所有從伺服器,因為 Sentinel 可以通過詢問主伺服器來獲得所有從伺服器的資訊。每個Sentinel會以每兩秒一次的頻率,通過釋出與訂閱功能,向被它監視的所有主伺服器和從伺服器的__sentinel__:hello頻道傳送一條資訊,資訊中包含了Sentinel的IP地址、埠號和執行ID(runid)。

3)每個Sentinel都訂閱了被它監視的所有主伺服器和從伺服器的__sentinel__:hello 頻道,查詢之前未出現過的sentinel(looking for unknown sentinels)。當一個Sentinel發現一個新的Sentinel時,它會將新的Sentinel新增到一個列表中,這個列表儲存了Sentinel已知的,監視同一個主伺服器的所有其他 Sentinel 。Sentinel傳送的資訊中還包括完整的主伺服器當前配置(configuration)。如果一個 Sentinel 包含的主伺服器配置比另一個Sentinel傳送的配置要舊,那麼這個 Sentinel 會立即升級到新配置上。

4)在將一個新 Sentinel 新增到監視主伺服器的列表上面之前,Sentinel 會先檢查列表中是否已經包含了和要新增的 Sentinel 擁有相同執行 ID 或者相同地址(包括 IP 地址和埠號)的 Sentinel ,如果是的話,Sentinel 會先移除列表中已有的那些擁有相同執行 ID或者相同地址的 Sentinel ,然後再新增新 Sentinel 。

多個sentinel之間連線

Sentinel之間只會互相建立命令連線,用於進行通訊。因為已經有主從伺服器作為傳送和接收HELLO資訊的中介,所以Sentinel之間不會建立訂閱連線。

檢測例項的狀態

Sentinel使用PING命令來檢測例項的狀態:如果例項在指定的時間內沒有返回回覆,或者返回錯誤的回覆,那麼該例項會被 Sentinel 判斷為下線。

Redis的Sentinel中關於下線(down)有兩個不同的概念:

1)主觀下線(Subjectively Down, 簡稱 SDOWN)指的是單個 Sentinel 例項對伺服器做出的下線判斷。

2)客觀下線(Objectively Down,簡稱 ODOWN)指的是多個Sentinel例項在對同一個伺服器做出SDOWN判斷,並且通過SENTINEL is-master-down-by-addr命令互相交流之後,得出的伺服器下線判斷。(一個 Sentinel可以通過向另一個Sentinel傳送SENTINEL is-master-down-by-addr命令來詢問對方是否認為給定的伺服器已下線。)

如果一個伺服器沒有在 master-down-after-milliseconds 選項所指定的時間內,對向它送PING命令的Sentinel返回一個有效回覆(valid reply),那麼Sentinel就會將這個伺服器標記為主觀下線。

伺服器對PING命令的有效回覆可以是以下三種回覆的其中一種:

1)返回 +PONG 。

2)返回 -LOADING 錯誤。

3)返回 -MASTERDOWN 錯誤。

如果伺服器返回除以上三種回覆之外的其他回覆,又或者在指定時間內沒有回覆Ping命令,那麼Sentinel認為伺服器返回的回覆無效(non-valid)。

注意:一個伺服器必須在master-down-after-milliseconds毫秒內,一直返回無效回覆才會被Sentinel標記為主觀下線。

舉個例子,如果master-down-after-milliseconds選項的值為30000毫秒(30秒),那麼只要伺服器能在每29秒之內返回至少一次有效回覆,這個伺服器就仍然會被認為是處於正常狀態的。

從主觀下線狀態切換到客觀下線狀態並沒有使用嚴格的法定人數演算法(strong quorum algorithm),而是使用了流言協議:如果 Sentinel 在給定的時間範圍內,從其他Sentinel那裡接收到了足夠數量的主伺服器下線報告,那麼Sentinel就會將主伺服器的狀態從主觀下線改變為客觀下線。如果之後其他Sentinel不再報告主伺服器已下線,那麼客觀下線狀態就會被移除。

客觀下線條件只適用於主伺服器:對於任何其他型別的Redis例項,Sentinel在將它們判斷為下線前不需要進行協商,所以從伺服器或者其他 Sentinel 永遠不會達到客觀下線條件。

只要一個Sentinel發現某個主伺服器進入了客觀下線狀態,這個Sentinel就可能會被其他Sentinel推選出,並對失效的主伺服器執行自動故障遷移操作。

故障轉移FAILOVER

一次故障轉移操作由以下步驟組成:

1)發現主伺服器已經進入客觀下線狀態。

2)基於Raft leader election協議 ,進行投票選舉

3)如果當選失敗,那麼在設定的故障遷移超時時間的兩倍之後,重新嘗試當選。如果當選成功,那麼執行以下步驟。

4)選出一個從伺服器,並將它升級為主伺服器。

5)向被選中的從伺服器傳送 SLAVEOF NO ONE 命令,讓它轉變為主伺服器。

6)通過釋出與訂閱功能,將更新後的配置傳播給所有其他Sentinel,其他Sentinel對它們自己的配置進行更新。

7)向已下線主伺服器的從伺服器傳送SLAVEOF命令,讓它們去複製新的主伺服器。

8)當所有從伺服器都已經開始複製新的主伺服器時, leader Sentinel 終止這次故障遷移操作

每當一個Redis例項被重新配置(reconfigured)—— 無論是被設定成主伺服器、從伺服器、又或者被設定成其他主伺服器的從伺服器 —— Sentinel 都會向被重新配置的例項傳送一個CONFIG REWRITE命令,從而確保這些配置會持久化在硬盤裡。

Sentinel使用以下規則來選擇新的主伺服器:
1)在失效主伺服器屬下的從伺服器當中,那些被標記為主觀下線、已斷線、或者最後一次回覆PING命令的時間大於五秒鐘的從伺服器都會被淘汰。
2)在失效主伺服器屬下的從伺服器當中,那些與失效主伺服器連線斷開的時長超過down-after選項指定的時長十倍的從伺服器都會被淘汰。
3)在經歷了以上兩輪淘汰之後剩下來的從伺服器中,我們選出複製偏移量(replication offset)最大的那個從伺服器作為新的主伺服器;如果複製偏移量不可用,或者從伺服器的複製偏移量相同,那麼帶有最小執行ID的那個從伺服器成為新的主伺服器。

Sentinel自動故障遷移的一致性特質:
1)Sentinel自動故障遷移使用Raft演算法來選舉領頭(leader)Sentinel ,從而確保在一個給定的週期(epoch)裡,只有一個領頭產生。
2)這表示在同一個週期中, 不會有兩個 Sentinel 同時被選中為領頭,並且各個 Sentinel 在同一個節點中只會對一個領頭進行投票。
3)更高的配置節點總是優於較低的節點,因此每個 Sentinel 都會主動使用更新的節點來代替自己的配置。
簡單來說,我們可以將Sentinel配置看作是一個帶有版本號的狀態。一個狀態會以最後寫入者勝出(last-write-wins)的方式(也即是,最新的配置總是勝出)傳播至所有其他Sentinel。

舉個例子:
1)當出現網路分割(network partitions)時,一個Sentinel可能會包含了較舊的配置,而當這個Sentinel接到其他Sentinel發來的版本更新的配置時,Sentinel就會對自己的配置進行更新。

2)如果要在網路分割出現的情況下仍然保持一致性, 那麼應該使用 min-slaves-to-write 選項,讓主伺服器在連線的從例項少於給定數量時停止執行寫操作,與此同時,應該在每個執行Redis主伺服器或從伺服器的機器上執行Redis Sentinel程序。

Sentinel狀態的持久化:
1)Sentinel 的狀態會被持久化在 Sentinel 配置檔案裡面。
2)每當Sentinel接收到一個新的配置,或者當領頭Sentinel為主伺服器建立一個新的配置時,這個配置會與配置節點一起被儲存到磁盤裡面。
3)這意味著停止和重啟Sentinel程序都是安全的。

Sentinel在非故障遷移的情況下對例項進行重新配置:
1)即使沒有自動故障遷移操作在進行,Sentinel總會嘗試將當前的配置設定到被監視的例項上面。
特別是:
根據當前的配置,如果一個從伺服器被宣告為主伺服器,那麼它會代替原有的主伺服器,成為新的主伺服器,並且成為原有主伺服器的所有從伺服器的複製物件。
2)那些連線了錯誤主伺服器的從伺服器會被重新配置, 使得這些從伺服器會去複製正確的主伺服器。
3)不過,在以上這些條件滿足之後,Sentinel在對例項進行重新配置之前仍然會等待一段足夠長的時間,確保可以接收到其他Sentinel發來的配置更新,從而避免自身因為儲存了過期的配置而對例項進行了不必要的重新配置。

#######sentinel實戰及配置講解

環境準備

sentinel配置

 

#建立sentinel的配置檔案目錄
[[email protected] ~]# mkdir /etc/redis/26380
#進入sentinel配置目錄
[[email protected] ~]# cd /etc/redis/26380/
#編輯配置檔案
[[email protected] 26380]# vim sentinel.conf
port 26380
dir "/etc/redis/26380"
sentinel monitor mymaster 127.0.0.1 6379 1
sentinel down-after-milliseconds mymaster 5000
#啟動sentinel
[[email protected] 26380]# redis-sentinel /etc/redis/26380/sentinel.conf &

 sentinel切換測試

 

#連線redis主庫
[[email protected] 26380]# redis-cli -p 6379
#關閉主庫
127.0.0.1:6379> SHUTDOWN
#登入原從庫6380
[[email protected] 26380]# redis-cli -p 6380
#檢視主從資訊
127.0.0.1:6380> info replication
# Replication
role:master //由此可見,原從庫6380已經被提升為主庫
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=3552,lag=0 //從庫變成了6381
master_repl_offset:3566
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:3565

#開啟舊主庫6379
[[email protected] 26380]# redis-server /etc/redis/6379/redis.conf
#連線舊主庫6379
[[email protected] 26380]# redis-cli -p 6379
#檢視主從資訊
127.0.0.1:6379> info replication
# Replication
role:slave //角色變成了slave
master_host:127.0.0.1
master_port:6380 //主庫的埠是6380
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:37819
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

#在新主6380上檢視主從資訊
[[email protected] 26380]# redis-cli -p 6380
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=45288,lag=1
slave1:ip=127.0.0.1,port=6379,state=online,offset=45421,lag=0 //6379自動加入了叢集
master_repl_offset:45421
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:45420

sentinel monitor mymaster 127.0.0.1 6379 2
Sentinel 去監視一個名為mymaster的主伺服器,這個主伺服器的IP地址為127.0.0.1,埠號為6379,而將這個主伺服器判斷為失效至少需要2個Sentinel同意(只要同意Sentinel的數量不達標,自動故障遷移就不會執行,不過要注意,無論你設定要多少個Sentinel同意才能判斷一個伺服器失效,一個 Sentinel 都需要獲得系統中多數(majority) Sentinel 的支援,才能發起一次自動故障遷移,並預留一個給定的配置節點(configuration Epoch,一個配置節點就是一個新主伺服器配置的版本號)。換句話說,在只有少數(minority)Sentinel程序正常運作的情況下,Sentinel 是不能執行自動故障遷移的。

sentinel down-after-milliseconds mymaster 5000
指定了Sentinel認為伺服器已經斷線所需的毫秒數。如果伺服器在給定的毫秒數之內,沒有返回Sentinel傳送的Ping命令的回覆,或者返回一個錯誤,那麼Sentinel將這個伺服器標記為主觀下線(subjectively down,簡稱SDOWN)。不過只有一個Sentinel將伺服器標記為主觀下線並不一定會引起伺服器的自動故障遷移:只有在足夠數量的Sentinel都將一個伺服器標記為主觀下線之後,伺服器才會被標記為客觀下線(objectively down, 簡稱 ODOWN ),這時自動故障遷移才會執行。

sentinel failover-timeout mymaster 180000 

自動故障切換的超時時間

sentinel parallel-syncs mymaster 1 
在執行故障轉移時,最多可以有多少個從伺服器同時對新的主伺服器進行同步,這個數字越小,完成故障轉移所需的時間就越長。如果從伺服器被設定為允許使用過期資料集(參見對 redis.conf 檔案中對 slave-serve-stale-data 選項的說明),那麼你可能不希望所有從伺服器都在同一時間向新的主伺服器傳送同步請求,因為儘管複製過程的絕大部分步驟都不會阻塞從伺服器,但從伺服器在載入主伺服器發來的 RDB 檔案時,仍然會造成從伺服器在一段時間內不能處理命令請求:如果全部從伺服器一起對新的主伺服器進行同步,那麼就可能會造成所有從伺服器在短時間內全部不可用的情況出現。可以通過將這個值設為1來保證每次只有一個從伺服器處於不能處理命令請求的狀態。

sentinel管理命令(不常用

#連線sentinel管理埠
[[email protected] 26380]# redis-cli -p 26380
#檢測狀態,返回PONG
127.0.0.1:26380> PING
PONG
#列出所有被監視的主伺服器
127.0.0.1:26380> SENTINEL masters
#列出所有被監視的從伺服器
127.0.0.1:26380> SENTINEL slaves mymaster
#返回給定名字的主伺服器的IP地址和埠號
127.0.0.1:26380> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6380"
#重置所有名字和給定模式
127.0.0.1:26380> SENTINEL reset mymaster
#當主伺服器失效時,在不詢問其他Sentinel意見的情況下,強制開始一次自動故障遷移。
127.0.0.1:26380> SENTINEL failover mymaster