所謂的高可用,也叫 HA(High Availability),是分布式系統架構設計中必須考慮的因素之一,它通常是指,通過設計減少系統不能提供服務的時間。
如果在實際生產中,如果 redis 只部署一個節點,當機器故障時,整改服務都不能提供服務了。這就是我們常說的單點故障。
如果 redis 部署了多台,當一台或幾台故障時,整個系統依然可以對外提供服務,這樣就提高了服務的可用性。
今天我們就聊聊 redis 高可用的三種模式:主從模式,*哨兵模式*,集群模式。
一、主從模式
一般,系統的高可用都是通過部署多台機器實現的。redis 為了避免單點故障,也需要部署多台機器。
因為部署了多台機器,所以就會涉及到不同機器的的數據同步問題。
為此,redis 提供了 Redis 提供了復制(replication)功能,當一台 redis 數據庫中的數據發生了變化,這個變化會被自動的同步到其他的 redis 機器上去。
redis 多機器部署時,這些機器節點會被分成兩類,一類是主節點(master 節點),一類是從節點(slave 節點)。一般主節點可以進行讀、寫操作,而從節點只能進行讀操作。同時由於主節點可以寫,數據會發生變化,當主節點的數據發生變化時,會將變化的數據同步給從節點,這樣從節點的數據就可以和主節點的數據保持一致了。一個主節點可以有多個從節點,但是一個從節點會只會有一個主節點,也就是所謂的一主多從結構。

1.1.機器規划
|機器名稱|IP|端口|
| ---- | ---- | ---- |
| master | 192.168.1.10 | 6379 |
| slave1 | 192.168.1.11 | 6379 |
| slave2 | 192.168.1.12 | 6379 |
| slave3 | 192.168.1.13 | 6379 |
1.2.配置
主節點配置
主節點按照正常的配置配好即可。
從節點配置
使用默認的配置啟動機器,機器都是主節點。如果想要讓機器變成從節點,需要在 conf 服務器上配置主從復制的相關參數。
-
在從節點的配置文件 redis.conf 中指定主節點的信息(如果需要的話,可以配置主節點的登錄密碼,主從復制相關的參數)。三台從節點的配置是一樣的。
-
也可以不配置上面的文件,使用 redis-server 命令,在啟動從節點時,通過參數--slaveof 指定主節點是誰。。
-
也可以不配上面的文件,正常啟動 redis 機器,然后通過
redis-cli
的命令行執行slaveof 192.168.1.10 6379
指定主節點是誰。
系統運行時,如果 master 掛掉了,可以在一個從庫(如 slave1)上手動執行命令slaveof no one
,將 slave1 變成新的 master;在 slave2 和 slave3 上分別執行slaveof 192.168.1.11 6379
將這兩個機器的主節點指向的這個新的 master;同時,掛掉的原 master 啟動后作為新的 slave 也指向新的 master 上。
執行命令slaveof no one
命令,可以關閉從服務器的復制功能。同時原來同步的所得的數據集都不會被丟棄。
1.3.機器啟動
首先啟動主節點,然后一台一台啟動從節點。
1.4.主從復制的機制

-
從數據庫連接主數據庫,發送 SYNC 命令;
-
主數據庫接收到 SYNC 命令后,可以執行 BGSAVE 命令生成 RDB 文件並使用緩沖區記錄此后執行的所有寫命令;
-
主數據庫 BGSAVE 執行完后,向所有從數據庫發送快照文件,並在發送期間繼續記錄被執行的寫命令;
-
從數據庫收到快照文件后丟棄所有舊數據,載入收到的快照;
-
主數據庫快照發送完畢后開始向從數據庫發送緩沖區中的寫命令;
-
從數據庫完成對快照的載入,開始接受命令請求,並執行來自主數據庫緩沖區的寫命令;(從數據庫初始化完成)
-
主數據庫每執行一個寫命令就會向從數據庫發送相同的寫命令,從數據庫接收並執行收到的寫命令(從數據庫初始化完成后的操作)
-
出現斷開重連后,2.8 之后的版本會將斷線期間的命令傳給從數據庫,增量復制。
-
主從剛剛連接的時候,進行全量同步;全同步結束后,進行增量同步。當然,如果有需要,slave 在任何時候都可以發起全量同步。Redis 的策略是,無論如何,首先會嘗試進行增量同步,如不成功,要求從機進行全量同步。
1.5.主從模式的優缺點
優點
-
支持主從復制,主機會自動將數據同步到從機,可以進行讀寫分離;
-
為了分載 Master 的讀操作壓力,Slave 服務器可以為客戶端提供只讀操作的服務,寫服務依然必須由 Master 來完成;
-
Slave 同樣可以接受其他 Slaves 的連接和同步請求,這樣可以有效地分載 Master 的同步壓力;
-
Master 是以非阻塞的方式為 Slaves 提供服務。所以在 Master-Slave 同步期間,客戶端仍然可以提交查詢或修改請求;
-
Slave 同樣是以阻塞的方式完成數據同步。在同步期間,如果有客戶端提交查詢請求,Redis 則返回同步之前的數據。
缺點
-
Redis 不具備自動容錯和恢復功能,主機從機的宕機都會導致前端部分讀寫請求失敗,需要等待機器重啟或者手動切換前端的 IP 才能恢復;
-
主機宕機,宕機前有部分數據未能及時同步到從機,切換 IP 后還會引入數據不一致的問題,降低了系統的可用性;
-
如果多個 Slave 斷線了,需要重啟的時候,盡量不要在同一時間段進行重啟。因為只要 Slave 啟動,就會發送 sync 請求和主機全量同步,當多個 Slave 重啟的時候,可能會導致 Master IO 劇增從而宕機。
-
Redis 較難支持在線擴容,在集群容量達到上限時在線擴容會變得很復雜;
-
redis 的主節點和從節點中的數據是一樣的,降低的內存的可用性
二、哨兵模式
主從模式下,當主服務器宕機后,需要手動把一台從服務器切換為主服務器,這就需要人工干預,費事費力,還會造成一段時間內服務不可用。這種方式並不推薦,實際生產中,我們優先考慮哨兵模式。這種模式下,master 宕機,哨兵會自動選舉 master 並將其他的 slave 指向新的 master。
在主從模式下,redis 同時提供了哨兵命令redis-sentinel
,哨兵是一個獨立的進程,作為進程,它會獨立運行。其原理是哨兵進程向所有的 redis 機器發送命令,等待 Redis 服務器響應,從而監控運行的多個 Redis 實例。
哨兵可以有多個,一般為了便於決策選舉,使用奇數個哨兵。哨兵可以和 redis 機器部署在一起,也可以部署在其他的機器上。多個哨兵構成一個哨兵集群,哨兵直接也會相互通信,檢查哨兵是否正常運行,同時發現 master 宕機哨兵之間會進行決策選舉新的 master

哨兵模式的作用:
-
通過發送命令,讓 Redis 服務器返回監控其運行狀態,包括主服務器和從服務器;
-
當哨兵監測到 master 宕機,會自動將 slave 切換到 master,然后通過發布訂閱模式通過其他的從服務器,修改配置文件,讓它們切換主機;
-
然而一個哨兵進程對 Redis 服務器進行監控,也可能會出現問題,為此,我們可以使用多個哨兵進行監控。各個哨兵之間還會進行監控,這樣就形成了多哨兵模式。
哨兵很像 kafka 集群中的 zookeeper 的功能。
2.1.機器規划
| 機器名稱 | IP | 端口 |
| ---------- | ------------ | ----- |
| master | 192.168.1.10 | 6379 |
| slave 1 | 192.168.1.11 | 6379 |
| slave 2 | 192.168.1.12 | 6379 |
| slave 3 | 192.168.1.13 | 6379 |
| sentinel 1 | 192.168.1.14 | 26379 |
| sentinel 2 | 192.168.1.15 | 26379 |
| sentinel 3 | 192.168.1.16 | 26379 |
這里我們將哨兵進程和 redis 分別部署在不同的機器上,避免因為 redis 宕機導致 sentinel 進程不可用。
2.2.配置
redis.conf 的配置和上面主從模式一樣,不用變。這里主要說一下哨兵的配置。
每台機器的哨兵進程都需要一個哨兵的配置文件sentinel.conf
,三台機器的哨兵配置是一樣的。
2.3.機器啟動
首先啟動主節點,然后一台一台啟動從節點。
redis 集群啟動完成后,分別啟動哨兵集群所在機器的三個哨兵,使用redis-sentinel /path/to/sentinel.conf
命令。
2.4.哨兵模式的工作
-
每個 Sentinel(哨兵)進程以每秒鍾一次的頻率向整個集群中的 Master 主服務器,Slave 從服務器以及其他 Sentinel(哨兵)進程發送一個 PING 命令。
-
如果一個實例(instance)距離最后一次有效回復 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個實例會被 Sentinel(哨兵)進程標記為主觀下線(SDOWN)
-
如果一個 Master 主服務器被標記為主觀下線(SDOWN),則正在監視這個 Master 主服務器的所有 Sentinel(哨兵)進程要以每秒一次的頻率確認 Master 主服務器的確進入了主觀下線狀態
-
當有足夠數量的 Sentinel(哨兵)進程(大於等於配置文件指定的值)在指定的時間范圍內確認 Master 主服務器進入了主觀下線狀態(SDOWN), 則 Master 主服務器會被標記為客觀下線(ODOWN)
-
在一般情況下, 每個 Sentinel(哨兵)進程會以每 10 秒一次的頻率向集群中的所有 Master 主服務器、Slave 從服務器發送 INFO 命令。
-
當 Master 主服務器被 Sentinel(哨兵)進程標記為客觀下線(ODOWN)時,Sentinel(哨兵)進程向下線的 Master 主服務器的所有 Slave 從服務器發送 INFO 命令的頻率會從 10 秒一次改為每秒一次。
-
若沒有足夠數量的 Sentinel(哨兵)進程同意 Master 主服務器下線, Master 主服務器的客觀下線狀態就會被移除。若 Master 主服務器重新向 Sentinel(哨兵)進程發送 PING 命令返回有效回復,Master 主服務器的主觀下線狀態就會被移除。
假設 master 宕機,sentinel 1 先檢測到這個結果,系統並不會馬上進行 failover(故障轉移)選出新的 master,僅僅是QQ賬號地圖主觀的認為 master 不可用,這個現象成為主觀下線。當后面的哨兵也檢測到主服務器不可用,並且數量達到一定值時,那么哨兵之間就會進行一次投票,投票的結果由 sentinel 1 發起,進行 failover 操作。切換成功后,就會通過發布訂閱模式,讓各個哨兵把自己監控的從服務器實現切換主機,這個過程稱為客觀下線。這樣對於客戶端而言,一切都是透明的。
2.5.主從模式的優缺點
優點
-
哨兵模式是基於主從模式的,所有主從的優點,哨兵模式都具有。
-
主從可以自動切換,系統更健壯,可用性更高。
缺點
-
具有主從模式的缺點,每台機器上的數據是一樣的,內存的可用性較低。
-
Redis 較難支持在線擴容,在集群容量達到上限時在線擴容會變得很復雜。
三、集群模式
先說一個誤區:Redis 的集群模式本身沒有使用一致性 hash 算法,而是使用 slots 插槽。這是很多人的一個誤區。這里先留個坑,后面我會出一期《 redis 系列之——一致性 hash 算法》。
Redis 的哨兵模式基本已經可以實現高可用,讀寫分離 ,但是在這種模式下每台 Redis 服務器都存儲相同的數據,很浪費內存,所以在 redis3.0 上加入了 Cluster 集群模式,實現了 Redis 的分布式存儲,對數據進行分片,也就是說每台 Redis 節點上存儲不同的內容;

這里的 6 台 redis 兩兩之間並不是獨立的,每個節點都會通過集群總線(cluster bus),與其他的節點進行通信。通訊時使用特殊的端口號,即對外服務端口號加 10000。例如如果某個 node 的端口號是 6379,那么它與其它 nodes 通信的端口號是 16379。nodes 之間的通信采用特殊的二進制協議。
對客戶端來說,整個 cluster 被看做是一個整體,客戶端可以連接任意一個 node 進行操作,就像操作單一 Redis 實例一樣,當客戶端操作的 key 沒有分配到該 node 上時,Redis 會返回轉向指令,指向正確的 node,這有點兒像瀏覽器頁面的 302 redirect 跳轉。
根據官方推薦,集群部署至少要 3 台以上的 master 節點,最好使用 3 主 3 從六個節點的模式。測試時,也可以在一台機器上部署這六個實例,通過端口區分出來。
3.1.機器規划
| 機器名稱 | IP | 端口 |
| -------- | ------------ | ---- |
| master 1 | 192.168.1.11 | 6379 |
| master 2 | 192.168.1.12 | 6379 |
| master 3 | 192.168.1.13 | 6379 |
| slave 1 | 192.168.1.21 | 6379 |
| slave 2 | 192.168.1.22 | 6379 |
| slave 3 | 192.168.1.23 | 6379 |
3.2.配置
修改redis.conf
的配置文件:
3.3.機器啟動
6 個 Redis 服務分別啟動成功之后,這時雖然配置了集群開啟,但是這六台機器還是獨立的。使用集群管理命令將這 6 台機器添加到一個集群中。
借助 redis-tri.rb 工具可以快速的部署集群。
只需要執行redis-trib.rb create --replicas 1 192.168.1.11:6379 192.168.1.21:6379 192.168.1.12:6379 192.168.1.22:6379 192.168.1.13:6379 192.168.1.23:6379
就可以成功創建集群。
該命令執行創建完成后會有響應的日志,通過相關的日志就可以看出集群中機器的關系(不一定和上圖對應),執行的日志如下:
執行完成后自動生成配置的 redis-cluster.conf 文件。
登錄集群:redis-cli -c -h 192.168.1.11 -p 6379 -a 123456 # -c,使用集群方式登錄
。
查看集群信息:192.168.1.11:6379> CLUSTER INFO #集群狀態
。
列出節點信息:192.168.1.11:6379> CLUSTER NODES #列出節點信息
。
添加數據:
獲取數據:
3.4.運行機制
在 Redis 的每一個節點上,都有這么兩個東西,一個是插槽(slot),它的的取值范圍是:0-16383,可以從上面redis-trib.rb
執行的結果看到這 16383 個 slot 在三個 master 上的分布。還有一個就是 cluster,可以理解為是一個集群管理的插件,類似的哨兵。
當我們的存取的 Key 到達的時候,Redis 會根據 crc16 的算法對計算后得出一個結果,然后把結果和 16384 求余數,這樣每個 key 都會對應一個編號在 0-16383 之間的哈希槽,通過這個值,去找到對應的插槽所對應的節點,然后直接自動跳轉到這個對應的節點上進行存取操作。
當數據寫入到對應的 master 節點后,這個數據會同步給這個 master 對應的所有 slave 節點。
為了保證高可用,redis-cluster 集群引入了主從模式,一個主節點對應一個或者多個從節點。當其它主節點 ping 主節點 master 1 時,如果半數以上的主節點與 master 1 通信超時,那么認為 master 1 宕機了,就會啟用 master 1 的從節點 slave 1,將 slave 1 變成主節點繼續提供服務。
如果 master 1 和它的從節點 slave 1 都宕機了,整個集群就會進入 fail 狀態,因為集群的 slot 映射不完整。如果集群超過半數以上的 master 掛掉,無論是否有 slave,集群都會進入 fail 狀態。
redis-cluster 采用去中心化的思想,沒有中心節點的說法,客戶端與 Redis 節點直連,不需要中間代理層,客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可。
3.5.集群擴縮容
對 redis 集群的擴容就是向集群中添加機器,縮容就是從集群中刪除機器,並重新將 16383 個 slots 分配到集群中的節點上(數據遷移)。
擴縮容也是使用集群管理工具 redis-tri.rb。
擴容時,先使用redis-tri.rb add-node
將新的機器加到集群中,這是新機器雖然已經在集群中了,但是沒有分配 slots,依然是不起做用的。在使用 redis-tri.rb reshard
進行分片重哈希(數據遷移),將舊節點上的 slots 分配到新節點上后,新節點才能起作用。
縮容時,先要使用 redis-tri.rb reshard
移除的機器上的 slots,然后使用redis-tri.rb add-del
移除機器。
3.8.集群模式的優缺點
優點
采用去中心化思想,數據按照 slot 存儲分布在多個節點,節點間數據共享,可動態調整數據分布;
可擴展性:可線性擴展到 1000 多個節點,節點可動態添加或刪除;
高可用性:部分節點不可用時,集群仍可用。通過增加 Slave 做 standby 數據副本,能夠實現故障自動 failover,節點之間通過 gossip 協議交換狀態信息,用投票機制完成 Slave 到 Master 的角色提升;
降低運維成本,提高系統的擴展性和可用性。
缺點
1.Redis Cluster 是無中心節點的集群架構,依靠 Goss 協議(謠言傳播)協同自動化修復集群的狀態
但 GosSIp 有消息延時和消息冗余的問題,在集群節點數量過多的時候,節點之間需要不斷進行 PING/PANG 通訊,不必須要的流量占用了大量的網絡資源。雖然 Reds4.0 對此進行了優化,但這個問題仍然存在。
2.數據遷移問題
Redis Cluster 可以進行節點的動態擴容縮容,這一過程,在目前實現中,還處於半自動狀態,需要人工介入。在擴縮容的時候,需要進行數據遷移。
而 Redis 為了保證遷移的一致性,遷移所有操作都是同步操作,執行遷移時,兩端的 Redis 均會進入時長不等的阻塞狀態,對於小 Key,該時間可以忽略不計,但如果一旦 Key 的內存使用過大,嚴重的時候會接觸發集群內的故障轉移,造成不必要的切換。
四、總結
主從模式:master 節點掛掉后,需要手動指定新的 master,可用性不高,基本不用。
哨兵模式:master 節點掛掉后,哨兵進程會主動選舉新的 master,可用性高,但是每個節點存儲的數據是一樣的,浪費內存空間。數據量不是很多,集群規模不是很大,需要自動容錯容災的時候使用。
集群模式:數據量比較大,QPS 要求較高的時候使用。 Redis Cluster 是 Redis 3.0 以后才正式推出,時間較晚,目前能證明在大規模生產環境下成功的案例還不是很多,需要時間檢驗。
完成,收工!