高可用性(HA),原本是系統的一個特性,旨在確保在高於平均水平的時間內保持約定的執行效能水平,通常是正常執行時間。
Redis 作為一個記憶體資料庫,其資料通常儲存在記憶體中,一旦發生故障,可能導致資料丟失或服務中斷,避免單點故障至關重要,這樣系統才能順利快速地恢復。
Redis 高可用 是指 Redis 透過一系列技術手段確保在面臨故障的情況下也能持續提供服務的能力。
由於我們現在已經進入了一個分散式系統,並且需要考慮許多錯誤,因此在這個拓撲結構中需要考慮一些新問題,以前簡單的事情現在變得更加複雜。
爲了保證 Redis 的高可用,它主要採用了以下三種手段:
Redis 主從複製
Redis 哨兵模式
Redis 叢集Cluster
接下來,我們逐個來分析看看。
1、Redis 主從複製
主從複製是 Redis 多機執行中最基礎的功能,它是把多個 Redis 節點組成一個 Redis 叢集,在這個叢集當中有一個主節點用來進行資料的操作,其他從節點用於同步主節點的內容,並且提供給客戶端進行資料查詢。
Redis 主從同步分為:
全量複製:首次資料同步時
增量複製:只需把主從庫網路斷連期間主庫收到的命令,同步給從庫
注意:在2.8版本之前只有全量複製,而2.8版本後有全量和增量複製
1.1 全量複製
全量複製主要的實施流程,包括以下幾個方面:
建立主從關係
當我們啟動多個 Redis 例項的時候,它們相互之間就可以透過 replicaof(Redis 5.0 之前使用 slaveof)命令形成主庫和從庫的關係
/* * 主:例項 1(ip:172.168.0.1) * 從:例項 2(ip:172.168.0.2) * 在從庫上執行以下命令 */ replicaof 172.16.0.1 6379
全量複製過程
1)主從庫間建立連線、協商同步
從庫給主庫傳送 psync 命令,表示要進行資料同步,主庫根據這個命令的引數來啟動複製。
psync 命令包含了主庫的 runID 和複製進度 offset 兩個引數:
runID,是每個 Redis 例項啟動時都會自動生成的一個隨機 ID,用來唯一標記這個例項
offset,此時設為 -1,表示第一次複製
2)主庫將所有資料同步給從庫
主庫執行 bgsave 命令,生成 RDB 檔案,接著將檔案發給從庫。從庫接收到 RDB 檔案後,會先清空當前資料庫,然後載入 RDB 檔案。
在主庫將資料同步給從庫的過程中,主庫不會被阻塞,仍然可以正常接收請求,否則,Redis 的服務就被中斷了。但是,這些請求中的寫操作並沒有記錄到剛剛生成的 RDB 檔案中。爲了保證主從庫的資料一致性,主庫會在記憶體中用專門的 replication buffer,記錄 RDB 檔案生成後收到的所有寫操作。
3)主庫會把第二階段執行過程中新收到的寫命令,再發送給從庫
當主庫完成 RDB 檔案傳送後,就會把此時 replication buffer 中的修改操作發給從庫,從庫再重新執行這些操作。
1.2 增量複製
此功能在 Redis 2.8 版本才引入,主要爲了控制主從複製的成本開銷。網路斷了之後,主從庫會採用增量複製的方式繼續同步。
先來看一個概念: replication buffer
。
replication_backlog 複製積壓緩衝區。命令一方面會傳輸給從節點,另外還會記錄在這個複製積壓緩衝區裡。Redis 使用一個環形緩衝區的結構儲存最近的一些命令。在緩衝區中,對位元組進行編號,這個編號在 Redis 中叫複製偏移量。
是否滿足增量同步的條件:
從節點 replid 和 主節點的 replid 相同
複製偏移量 offset 在複製積壓緩衝區的 backlog_off 和 offset 範圍之間。
2、Redis 哨兵模式
哨兵模式是redis高可用的實現方式之一,使用一個或者多個哨兵(Sentinel)例項組成的系統,對redis節點進行監控,在主節點出現故障的情況下,能將從節點中的一個升級為主節點,進行故障轉義,保證系統的可用性。
2.1 哨兵實現了什麼功能呢?
監控(Monitoring):確保主從例項是否運作正常
自動故障轉移(Automatic failover):如果主例項不可用並且足夠多的(法定數量)節點同意這是真的,Sentinel 節點可以啟動故障轉移
配置提供者(Configuration provider):客戶端在初始化時,透過連線哨兵來獲得當前Redis服務的主節點地址
通知(Notification):哨兵可以將故障轉移的結果傳送給客戶端
以這種方式使用 Redis Sentinel 可以進行故障檢測。此檢測涉及多個哨兵程序同意當前主例項不再可用。這個協議過程稱為 Quorum。這可以提高魯棒性並防止一臺機器行為異常導致無法訪問主 Redis 節點。
2.2 自動故障轉移
主觀下線
哨兵(Sentinel)節點會每秒一次的頻率向建立了命令連線的例項傳送 PING 命令,如果在down-after-milliseconds 毫秒內沒有做出有效響應,包括(PONG/LOADING/MASTERDOWN)以外的響應,哨兵就會將該例項在本結構體中的狀態標記為 SRI_S_DOWN 主觀下線。
客觀下線
當一個哨兵節點發現主節點處於主觀下線狀態時,會向其他的哨兵節點發出詢問,該節點是不是已經主觀下線了。
如果超過配置引數 quorum 個節點認為是主觀下線時,該哨兵節點就會將自己維護的結構體中該主節點標記為 SRI_O_DOWN 客觀下線 詢問命令:
SENTINEL is-master-down-by-addr <current_epoch> <run_id>
leader選舉
在認為主節點客觀下線的情況下,哨兵節點節點間會發起一次選舉,命令如下:
SENTINEL is-master-down-by-addr <current_epoch> <run_id>
只是這次會將自己的 run_id 帶進去,希望接受者將自己設定為主節點。
如果超過半數以上的節點返回將該節點標記為 leader 的情況下,會由該 leader 對故障進行轉移。
故障轉移
在從節點中挑選出新的主節點
a. 通訊正常
b. 優先順序排序
c. 優先順序相同是選擇offset最大的
將該節點設定成新的主節點 SLAVEOF no one,並確保在後續的INGO命令時,該節點返回狀態為master
將其他的從節點設定成從新的主節點複製, SLAVEOF命令
將舊的主節點變成新的主節點的從節點
3、Redis 叢集Cluster
Cluster 即 叢集模式。類似MySQL,Redis 叢集也是一種分散式資料庫方案,叢集透過分片(sharding)模式來對資料進行管理,並具備分片間資料複製、故障轉移和流量排程的能力。
Redis Cluster 允許 Redis 的水平擴充套件。
3.1 叢集Cluster 介紹
Redis 叢集將資料劃分爲 16384(2的14次方)個雜湊槽(slots),如果你有多個例項節點,那麼每個例項節點將管理其中一部分的槽位,槽位的資訊會儲存在各自所歸屬的節點中。以下圖為例,該叢集有4個 Redis 節點,每個節點負責叢集中的一部分資料,資料量可以不均勻。比如效能好的例項節點可以多分擔一些壓力。
一個Redis叢集一共有16384個雜湊槽,你可以有1 ~ n個節點來分配這些雜湊槽,可以不均勻分配,每個節點可以處理0個 到至多 16384 個槽點。當16384個雜湊槽都有節點進行管理的時候,叢集處於online 狀態。同樣的,如果有一個雜湊槽沒有被管理到,那麼叢集處於offline狀態。
上面圖中4個例項節點組成了一個叢集,叢集之間的資訊透過 Gossip協議 進行互動,這樣就可以在某一節點記錄其他節點的雜湊槽(slots)的分配情況。
3.2 Cluster模式擴充套件
單機的吞吐無法承受持續擴增的流量的時候,最好的辦法是從橫向(scale out) 和 縱向(scale up)兩方面進行擴充套件:
縱向擴充套件(scale up):將單個例項的硬體資源做提升,比如 CPU核數量、記憶體容量、SSD容量
橫向擴充套件(scale out):橫向擴增 Redis 例項數,這樣每個節點只負責一部分資料就可以(典型的分治思維)
4、總結
高可用一般來說有兩個含義:1)資料儘量不丟失,2)保證服務儘可能可用。
AOF 和 RDB 資料持久化保證了資料儘量不丟失,而多節點來保證服務儘可能提供服務。單個節點的系統吞吐量有限,容量也有限,缺點明顯,一旦發生故障會導致服務不可用。
使用讀寫分離之前,可以考慮其他方法增加Redis的讀負載能力:如儘量最佳化主節點(減少慢查詢、減少持久化等其他情況帶來的阻塞等)提高負載能力;使用Redis叢集同時提高讀負載能力和寫負載能力等
哨兵模式已經實現了故障自動轉移的能力,但業務規模的不斷擴充套件,使用者量膨脹,併發量持續提升,會出現了 Redis 響應慢的情況
使用 Redis Cluster 叢集,主要解決了大資料量儲存導致的各種慢問題,同時也便於橫向拓展。在面對千萬級甚至億級別的流量的時候,很多是在千百臺的例項節點組成的叢集上進行流量排程、服務治理的。