1、簡介:
1、是什么:
Redis-Sentinel是Redis官方推薦的高可用(HA)方案,當用Reids 做master-slave高可用方案時,假如master宕機了,redis本身(包括它的很多客服端)都沒有實現自動的主備切換,而Redis-Sentinel本身也是一個獨立運行的進程,它能監控多個master-slave集群,發現master宕機后能自動切換。
2、功能
- 不時監控redis是否按照預期的良好的運行。
- 如果發現某個redis節點運行出現狀況,能夠通知別外一個進程(如它的客戶端)。
- 能夠進行自動切換。當一個master節點不可用時,能夠選舉出master的多個slave(如果超過一個slave的話)中的一個來作為新的master,其它的slave節點會將他的master地址改為新提升為master的服務器的地址。
4、優缺點:
優點:
- 哨兵模式是基於主從模式的,所有主從的優點,哨兵模式都有。
- 主從可以自動切換,系統更健壯,可用性更高
缺點:
- redis較難支持在線擴容,在集群容量達上限時在線擴容變的很復雜。
2、原理:
1、哨兵的工作方式:
- 每個Sentinel(哨兵)進程以每秒鍾一次的頻率向整個redis集群中的master主服務器、slave從服務器以及其他的Sentinel(哨兵)進程發送一個ping命令。
- 如果一個實例距離最后一次有效回復ping命令的時間超過down-after-milliseconds選項所指定的值則這個實例會被Sentinel標記為主觀下線(SDOWN)。
- 如是是master主服務器被標記為SDOWN,則正在監控這個服務器的所有Sentinel都要以每秒一次的頻率確認服務器是否真的已經進入SDOWN(主觀下線狀態)。
- 當有足夠數量(≥配置文件配置值)的Sentinel在指定的時間內確認了master進入了SDOWN狀態,則master被標記為ODOWN(客觀下線狀態)。
- 在一般情況下,每個Sentinel會每10秒向redis 主服務器和從服務器發送Info命令。但是當master被標記為客觀下線時,頻率改為1秒一次。
- 若沒有足夠數量的Sentinel同意master服務器下線,則master的SDOWN狀態被移除,若master重新向Sentinel發送ping命令返回了有效回復,則master的SDOWN狀態被移除。
2、原理
- Sentinel集群通過給定的配置文件發現master,啟動時會監控master。通過向master發送info信息獲得該服務下面的所有從服務器。
- Sentinel集群通過命令連接向被監控的主從服務器發送hello信息(每秒一次),該信息包括Sentinel本身的ip、端口、id等內容,以此來向其他Sentinel宣告自己的存在。
- Sentinel集群通過訂閱連接接收其他Sentinel發送的hello信息,以此來發現監視同一個主服務器的其他Sentinel;集群之間會互相創建命令連接用於通信,因為已經有主從服務器作為發送和接收hello信息的中介,Sentinel之間不會創建訂閱連接。
- Sentinel集群使用Sentinel命令來檢測實例的狀態,如果指定的時間內(down-after-milliseconds)沒有回復或者返回錯誤回復,那么該實例被判為主觀下線SDOWN。
- 當failover主備切換被觸發后,failover並不會馬上進行,還需要Sentinel集群中另外quorum個其他Sentinel授權,成功后進入ODOWN客觀下線狀態,之后再進行failover。
- Sentinel向選為master的slave發送slaveof no one 命令,選擇slave的條件是首先會根據slave的優先級來排序,優先級越小排名越靠前。如果相同,則查看復制的下標,哪個接收master的復制數據越多哪個越靠前,如果兩個都一樣就選擇進程ID較小的。
- Sentinel被授權后會獲得宕機的master的一份最新配置版本號(config-epoch)當failover結束后,這個版本號將會用於最新的配置,通過廣播的形式通知其他Sentinel,其它的Sentinel則更新對應的master配置。
1-3是自動發現機制
- 以10秒一次的頻率,向被監控的master發送Info命令,根據回復獲取當前master信息。
- 以1秒一次的頻率,向所有的redis服務器包括 Sentinel 發送ping命令,通過回復判斷服務器是否在線
- 以2秒一次的頻率,通過 向所有被監控的master,slave服務器發送的當前Sentinel,master信息的消息。
4、是檢測機制,5、6是failover機制,7是更新配置機制。
注意:
- 因為redis采用的是異步復制,沒有辦法避免數據的丟失。但可以通過以下配置來使得數據不會丟失:min-slaves-to-write 1 ; min-slaves-max-lag 10。
- 一個redis無論是master還是slave,都必須在配置中指定一個slave優先級。
- 要注意到master也是有可能通過failover變成slave的。
- 如果一個redis的slave優先級配置為0,那么它將永遠不會被選為master,但是它依然會從master哪里復制數據。
3、SDOWN和ODOWN
- sentinel對於不可用有兩種不同的看法,一個叫主觀不可用(SDOWN),另外一個叫客觀不可用(ODOWN)。
- SDOWN是sentinel自己主觀上檢測到的關於master的狀態,ODOWN需要一定數量的sentinel達成一致意見才能認為一個master客觀上已經宕掉,各個sentinel之間通過命令
SENTINEL is_master_down_by_addr來獲得其它sentinel對master的檢測結果。- 從sentinel的角度來看,如果發送了PING心跳后,在一定時間內沒有收到合法的回復,就達到了SDOWN的條件。這個時間在配置中通過
is-master-down-after-milliseconds參數配置。- 從SDOWN切換到ODOWN不需要任何一致性算法,只需要一個gossip協議:如果一個sentinel收到了足夠多的sentinel發來消息告訴它某個master已經down掉了,SDOWN狀態就會變成ODOWN狀態。如果之后master可用了,這個狀態就會相應地被清理掉。
- 真正進行failover需要一個授權的過程,但是所有的failover都開始於一個ODOWN狀態。
- ODOWN狀態只適用於master,對於不是master的redis節點sentinel之間不需要任何協商,slaves和sentinel不會有ODOWN狀態。
4、配置版本號
- 為什么要先獲得大多數sentinel的認可時才能真正去執行failover呢?
- 當一個sentinel被授權后,它將會獲得宕掉的master的一份最新配置版本號,當failover執行結束以后,這個版本號將會被用於最新的配置。因為大多數sentinel都已經知道該版本號已經被要執行failover的sentinel拿走了,所以其他的sentinel都不能再去使用這個版本號。這意味着,每次failover都會附帶有一個獨一無二的版本號。我們將會看到這樣做的重要性。
- 而且,sentinel集群都遵守一個規則:如果sentinel A推薦sentinel B去執行failover,B會等待一段時間后,自行再次去對同一個master執行failover,這個等待的時間是通過
failover-timeout配置項去配置的。從這個規則可以看出,sentinel集群中的sentinel不會再同一時刻並發去failover同一個master,第一個進行failover的sentinel如果失敗了,另外一個將會在一定時間內進行重新進行failover,以此類推。- redis sentinel保證了活躍性:如果大多數sentinel能夠互相通信,最終將會有一個被授權去進行failover.
redis sentinel也保證了安全性:每個試圖去failover同一個master的sentinel都會得到一個獨一無二的版本號。5、配置傳播
- 一旦一個sentinel成功地對一個master進行了failover,它將會把關於master的最新配置通過廣播形式通知其它sentinel,其它的sentinel則更新對應master的配置。
- 一個faiover要想被成功實行,sentinel必須能夠向選為master的slave發送
SLAVEOF NO ONE命令,然后能夠通過INFO命令看到新master的配置信息。- 當將一個slave選舉為master並發送
SLAVEOF NO ONE后,即使其它的slave還沒針對新master重新配置自己,failover也被認為是成功了的,然后所有sentinels將會發布新的配置信息。新配在集群中相互傳播的方式,就是為什么我們需要當一個sentinel進行failover時必須被授權一個版本號的原因。
- 每個sentinel使用##發布/訂閱##的方式持續地傳播master的配置版本信息,配置傳播的##發布/訂閱##管道是:
__sentinel__:hello。- 因為每一個配置都有一個版本號,所以以版本號最大的那個為標准。
舉個栗子:
- 假設有一個名為mymaster的地址為192.168.1.50:6379。一開始,集群中所有的sentinel都知道這個地址,於是為mymaster的配置打上版本號1。
- 一段時候后mymaster死了,有一個sentinel被授權用版本號2對其進行failover。
- 如果failover成功了,假設地址改為了192.168.1.50:9000,此時配置的版本號為2,進行failover的sentinel會將新配置廣播給其他的sentinel
- 由於其他sentinel維護的版本號為1,發現新配置的版本號為2時,版本號變大了,說明配置更新了,於是就會采用最新的版本號為2的配置。
這意味着sentinel集群保證了第二種活躍性:一個能夠互相通信的sentinel集群最終會采用版本號最高且相同的配置。
6、Sentinel之間和Slaves之間的自動發現機制
- 雖然sentinel集群中各個sentinel都互相連接彼此來檢查對方的可用性以及互相發送消息。但是你不用在任何一個sentinel配置任何其它的sentinel的節點。因為sentinel利用了master的發布/訂閱機制去自動發現其它也監控了統一master的sentinel節點。通過向名為
__sentinel__:hello的管道中發送消息來實現。- 同樣,你也不需要在sentinel中配置某個master的所有slave的地址,sentinel會通過詢問master來得到這些slave的地址的。
- 每個sentinel通過向每個master和slave的發布/訂閱頻道
__sentinel__:hello每秒發送一次消息,來宣布它的存在。- 每個sentinel也訂閱了每個master和slave的頻道
__sentinel__:hello的內容,來發現未知的sentinel,當檢測到了新的sentinel,則將其加入到自身維護的master監控列表中。- 每個sentinel發送的消息中也包含了其當前維護的最新的master配置。如果某個sentinel發現自己的配置版本低於接收到的配置版本,則會用新的配置更新自己的master配置。
- 在為一個master添加一個新的sentinel前,sentinel總是檢查是否已經有sentinel與新的sentinel的進程號或者是地址是一樣的。如果是那樣,這個sentinel將會被刪除,而把新的sentinel添加上去。
7、網絡隔離時的一致性
例子:
- 有三個主機,每個主機分別運行一個redis和一個sentinel。初始狀態下redis3是master, redis1和redis2是slave。
- 之后redis3所在的主機網絡不可用了,sentinel1和sentinel2啟動了failover並把redis1選舉為master。
- Sentinel集群的特性保證了sentinel1和sentinel2得到了關於master的最新配置。但是sentinel3依然是舊的配置,因為它與外界隔離了。
當網絡恢復以后,我們知道sentinel3將會更新它的配置。但是,如果客戶端所連接的master被網絡隔離,會發生什么呢?
- 客戶端將依然可以向redis3寫數據,但是當網絡恢復后,redis3就會變成redis的一個slave,那么,在網絡隔離期間,客戶端向redis3寫的數據將會丟失。
- 因為redis采用的是異步復制,在這樣的場景下,沒有辦法避免數據的丟失。然而,你可以通過以下配置來配置redis3和redis1,使得數據不會丟失。
min-slaves-to-write 1 min-slaves-max-lag 10
- 通過上面的配置,當一個redis是master時,如果它不能向至少一個slave寫數據(上面的min-slaves-to-write指定了slave的數量),它將會拒絕接受客戶端的寫請求。
- 由於復制是異步的,master無法向slave寫數據意味着slave要么斷開連接了,要么不在指定時間內向master發送同步數據的請求了(上面的min-slaves-max-lag指定了這個時間)。
8、Slave選舉與優先級
當一個sentinel准備好了要進行failover,並且收到了其他sentinel的授權,那么就需要選舉出一個合適的slave來做為新的master。
slave的選舉主要會評估slave的以下幾個方面:
與master斷開連接的次數
Slave的優先級
數據復制的下標(用來評估slave當前擁有多少master的數據)
進程ID
如果一個slave與master失去聯系超過10次,並且每次都超過了配置的最大失聯時間(
down-after-milliseconds),如果sentinel在進行failover時發現slave失聯,那么這個slave就會被sentinel認為不適合用來做新master的。更嚴格的定義是,如果一個slave持續斷開連接的時間超過
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state就會被認為失去選舉資格。
符合上述條件的slave才會被列入master候選人列表,並根據以下順序來進行排序:
sentinel首先會根據slaves的優先級來進行排序,優先級越小排名越靠前。
如果優先級相同,則查看復制的下標,哪個從master接收的復制數據多,哪個就靠前。
如果優先級和下標都相同,就選擇進程ID較小的那個。
一個redis無論是master還是slave,都必須在配置中指定一個slave優先級。要注意到master也是有可能通過failover變成slave的。
如果一個redis的slave優先級配置為0,那么它將永遠不會被選為master。但是它依然會從master哪里復制數據。
3、配置
1、redis.conf 配置
################################# REPLICATION ################################# #復制選項,slave復制對應的master。 # slaveof <masterip> <masterport> #如果master設置了requirepass,那么slave要連上master,需要有master的密碼才行。masterauth就是用來配置master的密碼,這樣可以在連上master后進行認證。 # masterauth <master-password> #當從庫同主機失去連接或者復制正在進行,從機庫有兩種運行方式:1) 如果slave-serve-stale-data設置為yes(默認設置),從庫會繼續響應客戶端的請求。2) 如果slave-serve-stale-data設置為no,除去INFO和SLAVOF命令之外的任何請求都會返回一個錯誤”SYNC with master in progress”。 slave-serve-stale-data yes #作為從服務器,默認情況下是只讀的(yes),可以修改成NO,用於寫(不建議)。 slave-read-only yes #是否使用socket方式復制數據。目前redis復制提供兩種方式,disk和socket。如果新的slave連上來或者重連的slave無法部分同步,就會執行全量同步,master會生成rdb文件。有2種方式:disk方式是master創建一個新的進程把rdb文件保存到磁盤,再把磁盤上的rdb文件傳遞給slave。socket是master創建一個新的進程,直接把rdb文件以socket的方式發給slave。disk方式的時候,當一個rdb保存的過程中,多個slave都能共享這個rdb文件。socket的方式就的一個個slave順序復制。在磁盤速度緩慢,網速快的情況下推薦用socket方式。 repl-diskless-sync no #diskless復制的延遲時間,防止設置為0。一旦復制開始,節點不會再接收新slave的復制請求直到下一個rdb傳輸。所以最好等待一段時間,等更多的slave連上來。 repl-diskless-sync-delay 5 #slave根據指定的時間間隔向服務器發送ping請求。時間間隔可以通過 repl_ping_slave_period 來設置,默認10秒。 # repl-ping-slave-period 10 #復制連接超時時間。master和slave都有超時時間的設置。master檢測到slave上次發送的時間超過repl-timeout,即認為slave離線,清除該slave信息。slave檢測到上次和master交互的時間超過repl-timeout,則認為master離線。需要注意的是repl-timeout需要設置一個比repl-ping-slave-period更大的值,不然會經常檢測到超時。 # repl-timeout 60 #是否禁止復制tcp鏈接的tcp nodelay參數,可傳遞yes或者no。默認是no,即使用tcp nodelay。如果master設置了yes來禁止tcp nodelay設置,在把數據復制給slave的時候,會減少包的數量和更小的網絡帶寬。但是這也可能帶來數據的延遲。默認我們推薦更小的延遲,但是在數據量傳輸很大的場景下,建議選擇yes。 repl-disable-tcp-nodelay no #復制緩沖區大小,這是一個環形復制緩沖區,用來保存最新復制的命令。這樣在slave離線的時候,不需要完全復制master的數據,如果可以執行部分同步,只需要把緩沖區的部分數據復制給slave,就能恢復正常復制狀態。緩沖區的大小越大,slave離線的時間可以更長,復制緩沖區只有在有slave連接的時候才分配內存。沒有slave的一段時間,內存會被釋放出來,默認1m。 # repl-backlog-size 5mb #master沒有slave一段時間會釋放復制緩沖區的內存,repl-backlog-ttl用來設置該時間長度。單位為秒。 # repl-backlog-ttl 3600 #當master不可用,Sentinel會根據slave的優先級選舉一個master。最低的優先級的slave,當選master。而配置成0,永遠不會被選舉。 slave-priority 100 #redis提供了可以讓master停止寫入的方式,如果配置了min-slaves-to-write,健康的slave的個數小於N,mater就禁止寫入。master最少得有多少個健康的slave存活才能執行寫命令。這個配置雖然不能保證N個slave都一定能接收到master的寫操作,但是能避免沒有足夠健康的slave的時候,master不能寫入來避免數據丟失。設置為0是關閉該功能。 # min-slaves-to-write 3 #延遲小於min-slaves-max-lag秒的slave才認為是健康的slave。 # min-slaves-max-lag 102、sentinel.conf配置
port 20086 #默認端口26379 dir "/tmp" logfile "/var/log/redis/sentinel_20086.log" daemonize yes #格式:sentinel <option_name> <master_name> <option_value>;#該行的意思是:監控的master的名字叫做T1(自定義),地址為127.0.0.1:10086,行尾最后的一個2代表在sentinel集群中,多少個sentinel認為masters死了,才能真正認為該master不可用了。 sentinel monitor T1 127.0.0.1 10086 2 #sentinel會向master發送心跳PING來確認master是否存活,如果master在“一定時間范圍”內不回應PONG 或者是回復了一個錯誤消息,那么這個sentinel會主觀地(單方面地)認為這個master已經不可用了(subjectively down, 也簡稱為SDOWN)。而這個down-after-milliseconds就是用來指定這個“一定時間范圍”的,單位是毫秒,默認30秒。 sentinel down-after-milliseconds T1 15000 #failover過期時間,當failover開始后,在此時間內仍然沒有觸發任何failover操作,當前sentinel將會認為此次failoer失敗。默認180秒,即3分鍾。 sentinel failover-timeout T1 120000 #在發生failover主備切換時,這個選項指定了最多可以有多少個slave同時對新的master進行同步,這個數字越小,完成failover所需的時間就越長,但是如果這個數字越大,就意味着越多的slave因為replication而不可用。可以通過將這個值設為 1 來保證每次只有一個slave處於不能處理命令請求的狀態。 sentinel parallel-syncs T1 1 #sentinel 連接設置了密碼的主和從 #sentinel auth-pass <master_name> xxxxx #發生切換之后執行的一個自定義腳本:如發郵件、vip切換等 ##sentinel notification-script <master-name> <script-path> ##不會執行,疑問? #sentinel client-reconfig-script <master-name> <script-path> ##這個會執行例子:
port 20086 dir "/var/lib/sentinel_20086" logfile "/var/log/redis/sentinel_20086.log" daemonize yes sentinel monitor T1 127.0.0.1 10086 2 sentinel down-after-milliseconds T1 15000 sentinel failover-timeout T1 120000 sentinel parallel-syncs T1 1 #發生切換之后執行的一個自定義腳本:如發郵件、vip切換等 #sentinel notification-script <master-name> <script-path>主要配置sentinel monitor 主服務器的地址,其他配置按需要調整。
可添加 logfile 路徑作為 sentinel 的日志文件。
關鍵配置:sentinel monitor T1 127.0.0.1 10086 2
3、啟動命令
redis-sentinel sentinel.conf
注意:當一個master配置為需要密碼才能連接時,客戶端和slave在連接時都需要提供密碼。master通過requirepass設置自身的密碼,不提供密碼無法連接到這個master。slave通過masterauth來設置訪問master時的密碼。客戶端需要auth提供密碼,但是當使用了sentinel時,
由於一個master可能會變成一個slave,一個slave也可能會變成master,所以需要同時設置上述兩個配置項,並且sentinel需要連接master和slave,需要設置參數:sentinel auth-pass <master_name> xxxxx。
4、驗證
1、分別查看sentinel日志可看到如下記錄
可看到+monitor master mymaster 192.168.244.128 6379 quorum 2
+sentinel sentinel f578550308896289052a62744d7fd711f8e19d3f 192.168.244.130 26379 @ mymaster 192.168.244.128 6379
+sentinel sentinel b1538910277b0df2ea52c653cb2eed2a521c6ca1 192.168.244.131 26379 @ mymaster 192.168.244.128 6379
如下說明sentinel集群啟動成功
2、服務器info 命令查看信息
192.168.244.128
192.168.244.130
192.168.244.131
3、關閉主redis info命令查看
192.168.244.131 已經成為主服務器
192.168.244.130 已經成為131 的從服務器
4、可以查看主服務器停掉之后sentinel的日志是如何切換主備的
5、重新啟動后的主服務器變成了從服務器








