🎯 引言:Redis的高可用性為啥這么重要?
在現代高可用系統中,Redis 是一款不可或缺的分布式緩存與數據庫系統。無論是提升訪問速度,還是實現數據的高效持久化,Redis 都能輕松搞定。可是,當你把 Redis 用于關鍵業務時,它的高可用性就顯得尤為重要。為了避免系統出現單點故障,保障業務連續性,我們需要有一套高可用架構來確保 Redis 的穩定運行。
今天,我們就一起來探討一下 Redis 高可用架構 的幾種實現方式,看看如何設計一套健壯的 Redis 高可用方案,保證我們的 Redis 緩存一直在線,穩定運行。
🛠? 1. Redis 主從復制:簡單的高可用方案
1.1 主從復制工作原理
Redis 主從復制(Master-Slave Replication)是 Redis 實現高可用性最基礎的方案之一。在這種架構中,你會有一個主節點(Master)和一個或多個從節點(Slave)。主節點負責處理寫操作和數據更新,而從節點則負責從主節點同步數據并進行只讀操作。
當主節點發生故障時,可以將某個從節點提升為主節點(手動或自動),確保系統的持續可用。
主從復制基本架構
- 主節點(Master) :處理所有的寫操作(如
SET
、DEL
等命令)。 - 從節點(Slave) :只處理讀操作(如
GET
命令),并定期從主節點同步數據。
主從復制工作流程
(1)初始同步
當從節點(Slave)首次啟動并連接到主節點時,它需要將主節點的數據完全同步過來。這個過程稱為“全量同步”。
- 從節點連接主節點:從節點向主節點發起連接請求。
- 主節點進行快照(RDB) :主節點執行
SAVE
或BGSAVE
命令,將當前的內存數據(RDB 快照)保存到磁盤。 - 從節點復制快照:主節點將保存的數據發送給從節點,從節點將數據寫入本地數據庫。
- 建立同步通道:從節點在完成全量同步后,開始監聽主節點的變更。
(2)增量同步
從節點已經有了主節點的數據快照后,接下來的數據同步就是增量同步,只同步主節點上的變更數據。
- 主節點記錄變更操作:主節點每處理一個寫操作(如
SET
、DEL
),會將這個操作寫入復制日志(replication log
)中。 - 主節點發送變更命令給從節點:主節點將增量變更命令發送到所有的從節點。
- 從節點執行命令:從節點收到變更命令后,會在本地執行這些命令,保證數據的一致性。
(3)斷線恢復
如果從節點與主節點的連接丟失,Redis 會進行斷線恢復:
- 當從節點重新連接到主節點時,Redis 會判斷是進行全量同步還是增量同步。如果從節點沒有數據快照,它會進行全量同步;如果有數據快照,則會通過增量同步方式進行恢復。
主從復制的特點
- 只讀模式:從節點默認只能進行讀取操作(
GET
),不接受寫操作。寫操作必須通過主節點執行。 - 延遲問題:由于從節點是從主節點獲取數據的,主節點的寫操作會有一定的延遲才會在從節點上看到。
- 數據一致性:主從復制是最終一致性的,意味著從節點上的數據不會立即與主節點同步一致,在數據變更時可能會有短暫的不一致狀態。
主從復制的優勢
- 提高可用性和可靠性:從節點可以用來分擔主節點的讀取壓力,還可以在主節點故障時迅速切換,保證服務的可用性。
- 數據備份:從節點可以作為主節點的備份,提供數據冗余,防止主節點數據丟失。
- 負載均衡:多個從節點可以分擔讀取請求,從而降低主節點的負載。
主從復制使用場景
- 高可用架構:當主節點出現故障時,可以通過從節點提升一個新的主節點來實現故障切換。
- 讀寫分離:主節點處理寫操作,從節點處理讀操作,優化性能。
- 數據冗余:從節點可以作為數據的備份,一旦主節點出現問題,可以快速恢復數據。
1.2 主從復制搭建步驟
1、Redis 環境準備
-
下載安裝Redis
-
本次演示使用的版本是6.2.7版本(并且在本機環境模擬3個redis示例演示)
-
進行Redis目錄下創建 redis-cluster (mkdir redis-cluster)
-
復制原有redis.conf新建3個配置文件 redis-6379.conf redis-6380.conf redis-6381.conf
-
將配置文件放置到redis-cluster目錄下
-
編輯主節點(redis-6379.conf),主要修改以下配置項
port 6379 bind 127.0.0.1 pidfile ./redis-cluster/redis-6379.pid logfile ./redis-cluster/redis-6379.log dir ./redis-cluster/data/redis-6379
-
編輯從節點(redis-6380.conf)
port 6380 bind 127.0.0.1 pidfile ./redis-cluster/redis-6380.pid logfile ./redis-cluster/redis-6380.log dir ./redis-cluster/data/redis-6380 replicaof 127.0.0.1 6379
-
編輯從節點(redis-6381.conf)
port 6381 bind 127.0.0.1 pidfile ./redis-cluster/redis-6381.pid logfile ./redis-cluster/redis-6381.log dir ./redis-cluster/data/redis-6381 replicaof 127.0.0.1 6379
配置完成,主要配置項說明:
- port:每個 Redis 實例需要不同的端口。
- pidfile:每個實例需要獨立的 PID 文件。
- logfile:每個實例需要不同的日志文件。
- replicaof:設置主從復制指定主節點。
- dir:設置數據文件的存儲路徑。確保每個 Redis 實例的
dir
路徑存在(提前創建,用于存儲數據文件)
每個實例都需要不同的配置(特別是端口、PID 文件、日志文件和數據目錄),確保它們不會沖突。
2、啟動 Redis 實例
-
打開 命令終端
-
進入 Redis 所在的目錄
-
啟動3個實例
./src/redis-server ./redis-cluster/redis-6379.conf ./src/redis-server ./redis-cluster/redis-6380.conf ./src/redis-server ./redis-cluster/redis-6381.conf
-
檢查實例是否正常
你可以通過 redis cli 連接到每個實例,確認它們是否成功啟動。 -
檢查主從復制是否正常或者連接到主節點新增鍵值看同步是否成功
./src/redis-cli -p 6379 info replication ./src/redis-cli -p 6380 info replication
主節點
從節點
說明主從復制成功。
?? 2. Redis Sentinel:自動故障轉移的英雄
2.1 Redis Sentinel的工作原理
Redis Sentinel 是 Redis 提供的自動故障轉移系統。它監控 Redis 實例的健康狀況,一旦主節點發生故障,Sentinel 會自動將一個從節點提升為主節點,并更新所有從節點的信息,保證系統的高可用性。Sentinel 的作用不止于監控故障,它還可以提供自動故障轉移、配置發布以及客戶端連接的重定向。
哨兵部署架構
1、監控:Sentinel 會不斷檢查 master 和 slave 是否按預期工作。
2、自動故障恢復:如果 master 故障,Sentinel 會將一個 slave 提升為 master,當故障實例恢復后也會安裝新的 master 為主節點。
3、通知:Sentinel 充當 Redis 客戶端的服務發現來源,當集群發生故障轉移時,會將最新節點信息推送給 Redis 客戶端。
哨兵集群監控原理
Sentinel 基于心跳機制監測服務狀態,每隔1秒向集群的每個實例發送ping命令:
- 主觀下線:如果某 Sentinel 節點發現某實例未在規定時間響應,則認為該實例主觀下線。
- 客觀下線:若超過指定數量(quorum)的 Sentinel 都認為該實例主觀下線,則該實例客觀下線。quorum 值最好超過 Sentinel 實例數量的一半。
集群故障恢復原理
一旦發現 master 故障,Sentinel 需要在 salve 中選擇一個作為新的 master,選擇依據是這樣的:
- 首先會判斷 slave 節點與 master 節點斷開時間長短 ,如果超過指定值(downafter-milliseconds * 10)則會排除該 slave 節點
- 然后判斷 slave 節點的 slave-priority 值,越小優先級越高,如果是0則永不參與選舉
- 如果slave-priority一樣,則判斷 slave 節點的 offset 值 ,越大說明數據越新,優先級越高
- 最后是判斷slave節點的 運行id 大小,越小優先級越高。
當選出一個新的 master 之后,該如何實現切換呢?
流程如下:
- Sentinel給備選的 slave1 節點發送 slaveof no one 命令,讓該節點成為 master
- Sentinel給所有其它 slave 發送 slaveof 127.0.0.1 6380 命令,讓這些 slave 成為新 master 的從節點,開始從新的 master 上同步數據。
- 最后,Sentinel 將故障節點標記為 slave,當故障節點恢復后會自動成為新的 master 的 slave 節點。
2.2 配置 Redis Sentinel(哨兵)
部署多個 Redis 實例后,配置 Redis Sentinel 以實現高可用性,可以通過以下步驟來完成。哨兵模式的主要功能是監控 Redis 主節點和從節點的狀態,并在主節點宕機時自動切換到從節點。
- 你已經有了多個 Redis 實例(例如
6379
、6380
、6381
)。 - 你希望配置 Sentinel 來監控這些實例,并在主節點宕機時進行自動故障轉移。
每個 Redis 哨兵都需要配置一個 sentinel.conf
文件來監控主節點。你可以創建多個 Sentinel 配置文件,并通過它們來監控 Redis 實例。
設置哨兵配置文件(sentinel.conf
) 內容如下:
port 26379
bind 127.0.0.1
pidfile "./redis-cluster/sentinel-26379/sentinel-26379.pid"
logfile "./redis-cluster/sentinel-26379/sentinel-26379.log"
dir "./redis-cluster/sentinel-26379"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel parallel-syncs mymaster 1
復制文件進行 26380 和 26381 哨兵的配置。
port 26380
bind 127.0.0.1
pidfile "./redis-cluster/sentinel-26380/sentinel-26380.pid"
logfile "./redis-cluster/sentinel-26380/sentinel-26380.log"
dir "./redis-cluster/sentinel-26380"
sentinel monitor mymaster 127.0.0.1 6380 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
sentinel parallel-syncs mymaster 1
- sentinel monitor mymaster:這是 Sentinel 監控的主節點名稱,這里設置為
mymaster
,并且指定了主節點的 IP 和端口(127.0.0.1 6379
)。后面的數字2
表示至少需要 2 個哨兵節點確認主節點宕機后,才會進行故障轉移。 - sentinel down-after-milliseconds mymaster 5000:當主節點 5 秒沒有響應時,認為該節點宕機。
- sentinel failover-timeout mymaster 10000:故障轉移的超時時間。
- sentinel parallel-syncs mymaster 1:指定故障轉移時,最多有多少個從節點同步數據。
2.3 啟動 Redis Sentinel(哨兵)
-
你可以啟動多個 Sentinel 實例來提高容錯性。
./src/redis-sentinel ./redis-cluster/sentinel-26379.conf ./src/redis-sentinel ./redis-cluster/sentinel-26380.conf ./src/redis-sentinel ./redis-cluster/sentinel-26381.conf
-
驗證哨兵狀態查看是否發現主節點
./src/redis-cli -p 26379 sentinel masters
-
查看從節點狀態
./src/redis-cli -p 26379 sentinel slaves mymaster
5. 搭建完成,這說明 Sentinel 已經自動發現并管理了從節點 🎯
2.4 哨兵模式連接Redis
在Sentinel集群監管下的Redis主從集群,其節點會因為自動故障轉移而發生變化,Redis的客戶端必須感知這種變化,及時更新連接信息。
客戶端應用程序應該使用RedisSentinel模式連接Redis,而不是直接固定的Redis的IP。我們可以直接通過哨兵獲取到當前的主節點IP。可以使用命令:
./src/redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
我們通過一個測試來實現Spring Boot實現集成哨兵機制。
Maven依賴
<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.15.3</version></dependency>
配置文件添加配置項
spring:redis:sentinel:master: mymasternodes: 127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381host: 127.0.0.1port: 6379database: 1 # 默認使用 0 庫password:
測試連接代碼
@Configuration
@AutoConfigureBefore({RedisAutoConfiguration.class, RedissonAutoConfiguration.class})
public class RedissonConfig {protected final Logger logger = LoggerFactory.getLogger(this.getClass());@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private String port;@Value("${spring.redis.password}")private String password;@Value("${spring.redis.database}")private int database;@Value("${spring.redis.sentinel.master}")private String sentinelMaster;@Value("${spring.redis.sentinel.nodes}")private String sentinelNodes;@Value("${redisson.threads:4}")private int threads;@Value("${redisson.nettyThreads:5}")private int nettyThreads;@Value("${redisson.connectPoolSize:20}")private int connectPoolSize;@Value("${redisson.connectPoolIdleSize:5}")private int connectPoolIdleSize;@Value("${redisson.connectTimeout:10000}")private int connectTimeout;@Value("${redisson.retryAttempts:3}")private int retryAttempts;@Value("${redisson.retryInterval:1500}")private int retryInterval;@Value("${redisson.timeout:10000}")private int timeout;@Value("${redisson.pingConnectionInterval:30000}")private int pingConnectionInterval;@Bean(destroyMethod = "shutdown")@ConditionalOnMissingBean(RedissonClient.class)public RedissonClient redisson() throws IOException {Config config = new Config();int cpuCores = Runtime.getRuntime().availableProcessors();threads = (threads == 0 ? cpuCores * 2 : threads);nettyThreads = (nettyThreads == 0 ? cpuCores : nettyThreads);config.setThreads(threads);config.setNettyThreads(nettyThreads);config.setTransportMode(TransportMode.NIO);// 設置序列化(禁用class類型信息)config.setCodec(new SimpleRedisJsonCodec());if (StringUtils.isNotEmpty(sentinelMaster) && StringUtils.isNotEmpty(sentinelNodes)) {// 支持哨兵模式logger.info("RedissonClient init useSentinelServers");String[] sentinels = sentinelNodes.split(",");config.useSentinelServers().setMasterName(sentinelMaster).setDatabase(database).setPassword(StringUtils.isEmpty(password) ? null : password).setTimeout(timeout).addSentinelAddress(formatRedisUrls(sentinels));} else if (host.contains(",")) {// 集群模式logger.info("RedissonClient init useClusterServers");String[] clusterNodes = host.split(",");ClusterServersConfig cConfig = config.useClusterServers();for (String node : clusterNodes) {cConfig.addNodeAddress("redis://" + node + ":" + port);}cConfig.setPassword(password);cConfig.setMasterConnectionPoolSize(connectPoolSize);cConfig.setMasterConnectionMinimumIdleSize(connectPoolIdleSize);cConfig.setConnectTimeout(connectTimeout);cConfig.setRetryAttempts(retryAttempts);cConfig.setRetryInterval(retryInterval);cConfig.setTimeout(timeout);cConfig.setPingConnectionInterval(pingConnectionInterval);} else {// 單機模式logger.info("RedissonClient init useSingleServer");config.useSingleServer().setAddress("redis://" + host + ":" + port).setDatabase(database).setPassword(StringUtils.isEmpty(password) ? null : password).setConnectionPoolSize(connectPoolSize).setConnectionMinimumIdleSize(connectPoolIdleSize).setTimeout(timeout);}return Redisson.create(config);}/*** 格式化 Redis URL,確保前綴一致*/private String[] formatRedisUrls(String[] nodes) {return Arrays.stream(nodes).map(node -> node.startsWith("redis://") ? node : "redis://" + node).toArray(String[]::new);}
}
連接成功
2.5 測試故障轉移
你可以通過停掉主節點(6379
)來測試故障轉移的功能。停掉主節點后,Sentinel 會自動將從節點提升為新的主節點。
-
停止主節點(
6379
) -
Sentinel 會檢測到主節點宕機,并自動執行故障轉移,將選擇一個從節點升級為新的主節點。你可以通過以下命令查看新的 Sentinel 的主節點。可以看到新的主節點已經變成6381。
./src/redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster1) "127.0.0.1"2) "6381"
并且SpringBoot中自動感知到節點變化,業務可正常使用,不受到Redis節點宕掉的影響。
- 自動化:Sentinel 自動監控 Redis 狀態,發生故障時,自動完成故障轉移。
- 高可用:Redis Sentinel 可以防止單點故障,增強系統的穩定性。
? 3. Redis Cluster:實現水平擴展和高可用性的終極武器
3.1 Redis Cluster的工作原理
Redis Cluster 是 Redis 3.0 引入的一個新特性,它可以實現水平擴展并且在多個節點之間分配數據。Redis Cluster 是基于分片的架構,數據會自動分布到不同的節點上。每個節點都有一個主節點和若干從節點組成的高可用集群。
當某個節點發生故障時,Redis Cluster 可以自動將從節點提升為主節點,繼續保持服務的可用性。同時,Cluster 支持 自動分片,即每個節點負責一部分數據。
3.2 Redis Cluster的搭建步驟
持續更新中…
🚀 4. 實際應用案例:如何實現生產環境中的 Redis 高可用架構
在實際生產環境中,Redis 的高可用架構設計需要根據具體的需求來選擇適合的方案。比如,對于需要高吞吐量和低延遲的場景,使用 Redis Cluster 是一個不錯的選擇;而對于一些中小型應用,可以選擇 Redis Sentinel 來確保故障自動切換。
4.1 使用 Redis Sentinel 實現高可用
- 部署 Redis 實例:設置主從節點,并在至少 3 個機器上運行 Redis。
- 配置 Sentinel:配置 Sentinel 進行監控和故障轉移。
- 自動切換:當主節點宕機時,Sentinel 自動將從節點提升為主節點。
4.2 使用 Redis Cluster 實現高可用
- 分配數據分片:將數據分配到多個 Redis 節點上,每個節點負責不同的數據分片。
- 設置集群:通過
redis-trib
工具來創建 Redis 集群。 - 監控集群狀態:使用
redis-cli
檢查集群狀態,確保節點間通信正常。
🔒 5. 結論:如何選擇合適的 Redis 高可用方案?
每個系統對 Redis 高可用性的需求都不盡相同,因此選擇合適的架構尤為重要:
- 小型系統:可以選擇 Redis 主從復制,設置少量的從節點來提升讀取性能。
- 中型系統:使用 Redis Sentinel 來實現自動故障轉移,并增加更多的監控和故障處理功能。
- 大型系統:對于大規模的應用,建議使用 Redis Cluster 進行分片存儲與水平擴展,并結合 Sentinel 進行高可用性保障。
通過了解 Redis 的高可用架構,結合實際業務需求來進行部署,我們就能避免系統因為 Redis 故障導致的業務中斷,提升整體系統的可靠性。
? 總結:Redis 緩存一直在線,穩定運行
Redis 的高可用性不僅關乎緩存系統的穩定性,更是支撐業務連續性的關鍵。通過選擇合適的高可用架構,我們可以讓 Redis 在系統故障時仍然堅挺不倒,保證業務流暢運行。
希望你通過這篇文章了解了 Redis 主從復制、Sentinel 和 Cluster 的不同高可用實現方式,找到適合自己的方案,確保 Redis 在高負載下仍能保持穩定運行!
🌟 你的支持是我持續創作的動力,歡迎點贊、收藏、分享!