本套技術專欄是作者(秦凱新)平時工作的總結和昇華,並深度整理大量網上資源和專業書籍。通過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和叢集環境容量規劃等內容,請持續關注本套部落格。QQ郵箱地址:1120746959@qq.com,如有任何學術交流,可隨時聯絡。
1 Redis 哨兵
-
哨兵是redis叢集架構中非常重要的一個元件,主要功能如下:
-
叢集監控,負責監控redis master和slave程式是否正常工作
-
訊息通知,如果某個redis例項有故障,那麼哨兵負責傳送訊息作為報警通知給管理員
-
故障轉移,如果master node掛掉了,會自動轉移到slave node上
-
配置中心,如果故障轉移發生了,通知client客戶端新的master地址
-
-
哨兵本身也是分散式的,作為一個哨兵叢集去執行,互相協同工作
- 故障轉移時,判斷一個master node是當機了,需要大部分的哨兵都同意才行,涉及到了分散式選舉的問題
- 即使部分哨兵節點掛掉了,哨兵叢集還是能正常工作的,因為如果一個作為高可用機制重要組成部分的故障轉移系統本身是單點的,就會出現危機。
- 目前採用的是sentinal 2版本,sentinal 2相對於sentinal 1來說,重寫了很多程式碼,主要是讓故障轉移的機制和演算法變得更加健壯和簡單。
- 哨兵至少需要3個例項,來保證自己的健壯性
- 哨兵 + redis主從的部署架構,是不會保證資料零丟失的,只能保證redis叢集的高可用性
- 對於哨兵 + redis主從這種複雜的部署架構,儘量在測試環境和生產環境,都進行充足的測試和演練。
2 Redis讀寫一致性保證
2.1 資料丟失場景分析
-
非同步複製導致的資料丟失,因為master -> slave的複製是非同步的,所以可能有部分資料還沒複製到slave,master就當機了,此時這些部分資料就丟失了
-
腦裂導致的資料丟失,腦裂,也就是說,某個master所在機器突然脫離了正常的網路,跟其他slave機器不能連線,但是實際上master還執行著,此時哨兵可能就會認為master當機了,然後開啟選舉,將其他slave切換成了master。
這個時候,叢集裡就會有兩個master,也就是所謂的腦裂。此時雖然某個slave被切換成了master,但是可能client還沒來得及切換到新的master,還繼續寫向舊master的資料可能也丟失了,因此舊master再次恢復的時候,會被作為一個slave掛到新的master上去,自己的資料會清空,重新從新的master複製資料。
2.2 解決非同步複製和腦裂導致的資料丟失
-
min-slaves-to-write 1
-
min-slaves-max-lag 10
-
要求至少有1個slave,資料複製和同步的延遲不能超過10秒,如果說一旦所有的slave,資料複製和同步的延遲都超過了10秒鐘,那麼這個時候,master就不會再接收任何請求了。
-
減少非同步複製的資料丟失:
有了min-slaves-max-lag這個配置,就可以確保說,一旦slave複製資料和ack延時太長,就認為可能master當機後損失的資料太多了,那麼就拒絕寫請求,這樣可以把master當機時由於部分資料未同步到slave導致的資料丟失降低的可控範圍內
-
減少腦裂的資料丟失
如果一個master出現了腦裂,跟其他slave丟了連線,那麼上面兩個配置可以確保說,如果不能繼續給指定數量的slave傳送資料,而且slave超過10秒沒有給自己ack訊息,那麼就直接拒絕客戶端的寫請求
這樣腦裂後的舊master就不會接受client的新資料,也就避免了資料丟失
上面的配置就確保了,如果跟任何一個slave丟了連線,在10秒後發現沒有slave給自己ack,那麼就拒絕新的寫請求,因此在腦裂場景下,最多就丟失10秒的資料。
3 Redis哨兵核心機制
3.1 sdown和odown轉換機制
-
sdown是主觀當機,就一個哨兵如果自己覺得一個master當機了,那麼就是主觀當機
sdown達成的條件很簡單,如果一個哨兵ping一個master,超過了is-master-down-after-milliseconds指定的毫秒數之後,就主觀認為master當機
-
odown是客觀當機,如果quorum數量的哨兵都覺得一個master當機了,那麼就是客觀當機
sdown到odown轉換的條件很簡單,如果一個哨兵在指定時間內,收到了quorum指定數量的其他哨兵也認為那個master是sdown了,那麼就認為是odown了,客觀認為master當機
3.2 哨兵叢集的自動發現機制
-
哨兵互相之間的發現,是通過redis的pub/sub系統實現的,每個哨兵都會往__sentinel__:hello這個channel裡傳送一個訊息,這時候所有其他哨兵都可以消費到這個訊息,並感知到其他的哨兵的存在
-
每隔兩秒鐘,每個哨兵都會往自己監控的某個master+slaves對應的__sentinel__:hello channel裡傳送一個訊息,內容是自己的host、ip和runid還有對這個master的監控配置
-
每個哨兵也會去監聽自己監控的每個master+slaves對應的__sentinel__:hello channel,然後去感知到同樣在監聽這個master+slaves的其他哨兵的存在
-
每個哨兵還會跟其他哨兵交換對master的監控配置,互相進行監控配置的同步
3.3 slave->master選舉演算法
-
如果一個master被認為odown了,而且majority哨兵都允許了主備切換,那麼某個哨兵就會執行主備切換操作,此時首先要選舉一個slave來,會考慮slave的一些資訊
(1)跟master斷開連線的時長 (2)slave優先順序 (3)複製offset (4)run id 複製程式碼
-
如果一個slave跟master斷開連線已經超過了down-after-milliseconds的10倍,外加master當機的時長,那麼slave就被認為不適合選舉為master
(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state 複製程式碼
-
slave進行排序
(1)按照slave優先順序進行排序,slave priority越低,優先順序就越高 (2)如果slave priority相同,那麼看replica offset,哪個slave複製了越多的資料,offset越靠後,優先順序就越高 (3)如果上面兩個條件都相同,那麼選擇一個run id比較小的那個slave 複製程式碼
-
quorum和majority
majority:授權進行主從切換的最少的哨兵數量。
quorum:確認odown的最少的哨兵數量。
每次一個哨兵要做主備切換,首先需要quorum數量的哨兵認為odown,然後選舉出一個哨兵來做切換,這個哨兵還得得到majority哨兵的授權,才能正式執行切換
如果quorum < majority,比如5個哨兵,majority就是3,quorum設定為2,那麼就3個哨兵授權就可以執行切換
但是如果quorum >= majority,那麼必須quorum數量的哨兵都授權,比如5個哨兵,quorum是5,那麼必須5個哨兵都同意授權,才能執行切換
-
configuration epoch
哨兵會對一套redis master+slave進行監控,有相應的監控的配置
執行切換的那個哨兵,會從要切換到的新master(salve->master)那裡得到一個configuration epoch,這就是一個version號,每次切換的version號都必須是唯一的
如果第一個選舉出的哨兵切換失敗了,那麼其他哨兵,會等待failover-timeout時間,然後接替繼續執行切換,此時會重新獲取一個新的configuration epoch,作為新的version號。
-
configuraiton傳播
哨兵完成切換之後,會在自己本地更新生成最新的master配置,然後同步給其他的哨兵,就是通過之前說的pub/sub訊息機制
這裡之前的version號就很重要了,因為各種訊息都是通過一個channel去釋出和監聽的,所以一個哨兵完成一次新的切換之後,新的master配置是跟著新的version號的
其他的哨兵都是根據版本號的大小來更新自己的master配置的
4 總結
在此感謝石杉的講義,結合大資料在我們工業大資料平臺的實踐,總結成一篇實踐指南,方便以後查閱反思,後續我會根據本篇部落格進行程式碼技術實踐實現。
凱新雲技術社群