1 概述
高可用(High Availability)指系統在部分節點故障時仍能持續提供服務的能力。Redis 作為核心緩存組件,主流的高可用方案有主從復制、哨兵模式、集群模式三種。本文介紹主從復制、哨兵模式兩種高可用方案。
2 主從復制
通過 “一主多從” 架構實現數據同步,主節點處理寫請求并異步復制數據到從節點。從節點可承擔讀請求,提升系統吞吐量,但主節點故障時需人工切換,存在單點風險,適用于對自動化要求不高的輕量級場景。
- 數據冗余,實現數據的熱備份
- 讀寫分離,負載均衡。主節點負載讀寫,從節點負責讀,提高服務器并發量
2.1 部署架構(1主多從)
2.2 復制原理
Redis 的主從復制機制均采用異步復制,我們也稱為樂觀復制,這種復制方式意味著不能完全保證主庫和從庫數據的實時一致性。Redis的主從復制機制可以根據不同的業務場景可以采用不同的應對方式。下面是一些主要場景及其對應的實現方案:
- 首次配置完成主從庫之后的全量復制:在從庫第一次連接到主庫時,將采用psync復制方式進行全量復制。這意味著從庫會從頭開始復制主庫中的全部數據。
- 主從正常運行期間,準實時同步:在正常運行狀態下,從庫通過讀取主庫的緩沖區來進行增量復制。這個過程涉及復制主庫上發生的新的數據變更。
- 從庫第二次啟動(異常或主從網絡斷開后恢復):Append增量數據 + 準實時同步將通過讀取主庫的緩沖區進行部分復制。這種方式能夠快速同步中斷期間發生的數據變更,而不會對主庫造成重大影響。
2.3 數據同步
在主從服務器建立連接確認各自身份之后,就開始數據同步,從服務器向主服務器發送PSYNC命令,執行同步操作,并把自己的數據庫狀態更新至主服務器的數據庫狀態。Redis的主從同步分為:完整重同步(full resynchronization)和部分重同步(partial resynchronization)
2.3.1 全量同步
有兩種情況下是完整重同步,
- slave連接上master第一次復制的時候;
- 當主從斷線,重新連接復制的時候有可能是完整重同步(詳細說明見下節)
- 從服務器連接主服務器,發送SYNC命令
- 主服務器接收到SYNC命名后,開始執行bgsave命令生成RDB文件并使用緩沖區記錄此后執行的所有寫命令
- 主服務器basave執行完后,向所有從服務器發送快照文件,并在發送期間繼續記錄被執行的寫命令
- 從服務器收到快照文件后丟棄所有舊數據,載入收到的快照
- 主服務器快照發送完畢后,開始向從服務器發送緩沖區中的寫命令
- 從服務器完成對快照的載入,開始接收命令請求,并執行來自主服務器緩沖區的寫命令
2.3.2 全量同步
部分重同步是用于處理斷線后重復制的情況,先介紹幾個用于部分重同步的部分
- runid(replication ID),主服務器運行id,Redis實例在啟動時,隨機生成一個長度40的唯一字符串來標識當前節點
- offset,復制偏移量。主服務器和從服務器各自維護一個復制偏移量,記錄傳輸的字節數。當主節點向從節點發送N個字節數據時,主節點的offset增加N,從節點收到主節點傳來的N個字節數據時,從節點的offset增加N
- replication backlog buffer,復制積壓緩沖區。是一個固定長度的FIFO隊列,大小由配置參數repl-backlog-size指定,默認大小1MB。需要注意的是該緩沖區由master維護并且有且只有一個,所有slave共享此緩沖區,其作用在于備份最近主庫發送給從庫的數據
當slave連接到master,會執行PSYNC 發送記錄舊的master的runid(replication ID)和偏移量offset,這樣master能夠只發送slave所缺的增量部分。但是如果master的復制積壓緩存區沒有足夠的命令記錄,或者slave傳的runid(replication ID)不對,就會進行完整重同步,即slave會獲得一個完整的數據集副本。
2.4 總結
主從復制引入了數據冗余節點,提高了Redis的高可用性,同時提高了Redis服務的讀負載能力。但是Master節點掛了,只能人工干預恢復環境,因此,無人值守變成剛需。
3 哨兵模式
在主從復制基礎上引入獨立的哨兵集群,實時監控主從節點狀態。當主節點故障時,哨兵自動選舉新主節點并完成拓撲重構,實現無人值守的故障轉移。相比主從復制,其自動化程度更高,但仍受限于單主節點的容量上限。哨兵負責三個任務:監控,選主(選擇主庫)和通知。
- 監控:監控是指哨兵進程運行時,周期性(默認1秒)給所有主從節點發送 PING 命令,當主從節點收到PING 命令后,會發送一個響應命令給哨兵,這樣就可以檢測他們是否仍然在線運行。從庫沒有在規定時間內響應哨兵的PING命令,哨兵就會把它標記為"下線狀態";主庫沒有在規定時間呢響應哨兵的PING命令,哨兵就會判定主庫下線啟動選主流程。
- 選主:哨兵在主庫掛了以后,按照一定規則從從庫中選出作為新的主庫。
- 通知:哨兵將選出的新主庫連接信息發給其他從庫,從庫和新主庫建立連接,執行replicaof命令,復制數據。同時,哨兵會把新主庫的連接信息通知給客戶端,讓它們將操作請求發送給新主庫上。
3.3 部署架構
3.4 主節點下線
- SDown主觀下線(Subjectively Down):單個sentinel自己主觀上檢測到的關于master的狀態,從sentinel的角度來看,如果發送了PING心跳后,在一定時間內沒有收到合法的回復,就達到了SDOWN的條件。
- ODown客觀下線(Objectively Down):需要一定數量的sentinel,多個哨兵達成一致意見才能認為一個master客觀上已經宕機。quorum這個參數是進行客觀下線的一個依據,法定人數/法定票數 意思是至少有quorum個sentinel認為這個master有故障才會對這個master進行下線以及故障轉移。因為有的時候,某個sentinel節點可能因為自身網絡原因導致無法連接master,而此時master并沒有出現故障,所以這就需要多個sentinel都一致認為該master有問題,才可以進行下一步操作,這就保證了公平性和高可用。
3.5 選舉原理
當主節點被判斷客觀下線后,各個哨兵節點會進行協商,先選舉出一個==領導者哨兵節點(兵王)==并由該領導者也即被選舉出的兵王進行failover(故障轉移)。
3.5.1 哨兵選舉
監視該主節點的所有哨兵都有可能被選為領導者,選舉使用的算法是Raft算法;Raft算法的基本思路是先到先得:即在一輪選舉中,哨兵A向B發送成為領導者的申請、如果B沒有同意過其他哨兵,則會同意A成為領導者。
3.5.2 主節點選擇
3.6 總結
在主從復制的基礎上,哨兵引入了主節點的自動故障轉移,進一步提高了Redis的高可用性;但是哨兵的缺陷同樣很明顯:哨兵無法對從節點進行自動故障轉移,在讀寫分離場景下,從節點故障會導致讀服務不可用,這就需要對從節點做額外的監控、切換操作。 此外,哨兵仍然沒有解決寫操作無法負載均衡、存儲能力受到單機限制的問題。