Redis 作为一款高性能的内存数据库,在分布式架构中广泛应用。然而,单点 Redis 存在数据丢失、服务不可用等风险,因此需要高可用方案来保障 Redis 的稳定性。本文将详细介绍 Redis 的高可用方案,包括主从复制、哨兵模式、集群模式以及第三方方案,并深入解析其工作原理、适用场景、实现方式及完整代码。
Redis 提供了多种高可用方案,主要包括以下几种:
主从复制(Replication):通过复制主节点的数据到多个从节点,提高数据冗余和读取能力。
哨兵模式(Sentinel):在主从复制的基础上,增加自动故障转移能力。
集群模式(Cluster):采用分片技术,实现高可用和负载均衡。
第三方高可用方案:包括 Keepalived、Codis、Twemproxy 等。
方案 |
介绍 |
适用场景 |
---|---|---|
主从复制 | 通过复制主节点的数据到从节点,提供数据冗余,支持读写分离 |
适用于读多写少的应用,如缓存服务 |
哨兵模式 | 在主从复制的基础上,引入监控、自动故障转移和通知机制 |
适用于需要高可用但数据量不大的业务 |
集群模式 | 采用分片存储和多主架构,解决单机性能瓶颈,支持横向扩展 |
适用于大规模数据、高并发业务,如电商、社交网络 |
第三方方案 | 通过代理或负载均衡工具增强 Redis 高可用能力 |
适用于特定业务需求或混合架构 |
高可用性:在节点故障时,能够自动切换,确保服务不中断。
数据一致性:确保主从数据同步,避免数据丢失或不一致。
负载均衡:合理分配流量,避免单点压力过大。
扩展性:支持水平扩展,适应业务增长。
通过 replicaof 命令设置从节点,从节点自动同步主节点数据。
但主节点故障时,需要手动切换,从节点无法自动提升为主节点。
监控 Redis 服务器状态,发现主节点故障时,自动执行故障转移(failover)。
选举新的主节点,并通知客户端更新连接信息。
采用分片存储,不依赖单一节点,防止单点故障。
每个主节点有多个从节点,主节点故障时,自动选举新的主节点。
Keepalived:基于 VIP(虚拟 IP)实现 Redis 高可用,主节点故障时,VIP 迁移到新的主节点。
Codis:提供代理层,实现透明的 Redis 迁移和扩展。
数据同步:采用全量同步(RDB)和增量同步(AOF)机制。
复制偏移量:记录主从数据同步进度,支持断点续传。
异步复制:从节点异步拉取数据,提高性能。
从节点发送同步请求
从节点启动时,通过 replicaof 指定主节点,并向主节点发送 PSYNC 命令。
主节点创建数据快照(RDB 文件)并发送快照
如果是全量同步,主节点执行 BGSAVE 生成 RDB 文件,并通过 socket 传输到从节点。
从节点加载 RDB 快照并开始增量复制
从节点加载 RDB 快照后,继续请求主节点的增量数据。
主节点持续发送增量数据
主节点将新的写入命令追加到 replication backlog buffer,从节点获取并执行,以保持数据同步。
复制偏移量机制
主从节点维护 offset 记录同步进度,支持断点续传。
全量同步:当从节点第一次连接主节点,或者主节点复制缓冲区(backlog)中的数据不足以提供增量数据时,触发全量同步。
增量同步:从节点已部分同步过主节点数据时,主节点会仅发送增量部分。
心跳机制:从节点定期向主节点发送 PING,检查连接状态。
主节点处理从节点同步请求(replication.c)
void syncCommand(client *c) {
if (c->flags & CLIENT_SLAVE) return;
c->flags |= CLIENT_SLAVE;
listAddNodeTail(server.slaves, c);
}
从节点请求主节点数据(replication.c)
void replicationCron(void) {
listIter li;
listNode *ln;
listRewind(server.slaves, &li);
while ((ln = listNext(&li))) {
client *slave = ln->value;
if (slave->replstate == REPL_STATE_WAIT_BGSAVE_START) {
startBgsaveForReplication();
}
}
}
Sentinel 监控:周期性 PING 主从节点,检测存活状态。
主节点故障判定:基于投票机制确定主节点故障。
故障转移:选举新的主节点,并更新复制关系。
Redis 哨兵(Sentinel)是一种用于监控 Redis 服务器并实现自动故障转移的机制。其核心功能包括:
监控(Monitoring):定期检查主从节点的健康状态。
自动故障转移(Failover):主节点不可用时,选举新的主节点。
通知(Notification):通知 Redis 客户端新的主节点地址。
配置管理(Configuration Management):动态调整主从节点关系。
监控 Redis 服务器
哨兵定期向 Redis 服务器发送 PING 命令。
如果主节点无响应,哨兵会等待一段时间后再次确认。
主节点失效判定
多个哨兵通过投票确认主节点失效(subjectively down,简称 sdown)。
若多数哨兵达成共识,则判定为 objectively down(odown),进入故障转移流程。
选举新的主节点
通过 Raft 算法选举新的主节点,通常选择复制偏移量最大且响应最快的从节点。
通知从节点与客户端
将新主节点通知所有从节点,使其切换主节点。
更新 sentinel.conf 配置,并通知客户端连接新的主节点。
Sentinel 监控机制
故障转移机制
哨兵 PING 机制(sentinel.c)
void sentinelTimer(void) {
dictIterator *di = dictGetSafeIterator(server.sentinel.masters);
while((de = dictNext(di)) != NULL) {
sentinelRedisInstance *ri = dictGetVal(de);
if (mstime() - ri->last_pong_time > ri->down_after_period) {
ri->flags |= SRI_S_DOWN;
}
}
}
主节点选举(sentinel.c)
void sentinelFailoverSelectSlave(sentinelRedisInstance *ri) {
sentinelRedisInstance *candidate = NULL;
listIter li;
listNode *ln;
listRewind(ri->slaves, &li);
while((ln = listNext(&li))) {
sentinelRedisInstance *slave = listNodeValue(ln);
if (!candidate || slave->repl_offset > candidate->repl_offset) {
candidate = slave;
}
}
if (candidate) candidate->flags |= SRI_PROMOTED;
}
数据分片:基于哈希槽(hash slot)进行数据存储和路由。
Gossip 协议:节点之间通过 Gossip 协议交换状态信息。
自动故障转移:从节点自动提升为主节点,确保服务可用。
Redis Cluster 是 Redis 官方提供的分布式存储解决方案,支持数据分片(Sharding)和主从复制,具备高可用性。其主要特性包括:
数据分片(Sharding):采用哈希槽(Hash Slot)机制,将数据分布到不同的节点上。
无中心架构:节点间通过 Gossip 协议通信,避免单点故障。
自动故障转移:主节点故障时,从节点自动提升为主节点。
支持客户端直连:客户端可直连目标节点,减少代理层损耗。
哈希槽分片机制
Redis 集群将 16,384 个哈希槽(Hash Slots)均匀分配到多个节点。
每个 Key 通过 CRC16(Key) % 16384 计算哈希槽。
请求时,客户端根据 Key 的哈希槽直接定位目标节点。
Gossip 协议
节点间使用 Gossip 协议交换拓扑信息。
每个节点定期 PING 其他节点,更新状态。
当某个节点超过 NODE_TIMEOUT 未响应,标记为失败。
故障检测与转移
多个主节点达成共识后,判定某个节点失效。
从节点自动选举新主节点,更新哈希槽映射。
ASK 与 MOVED 重定向
MOVED:Key 所在的哈希槽已迁移,客户端重新请求新节点。
ASK:Key 处于数据迁移中,客户端需短暂访问目标节点。
集群启动
启动多个 Redis 实例,配置 cluster-enabled yes。
使用 redis-cli --cluster create 初始化集群。
数据存储与查询
客户端计算 Key 的哈希槽,直接访问目标节点。
目标节点若为从节点,会转发请求至主节点。
主从切换
发现主节点故障,从节点提升为主节点。
重新分配哈希槽,更新集群拓扑。
哈希槽计算(cluster.c)
int keyHashSlot(char *key, int keylen) {
return crc16(key, keylen) % 16384;
}
Gossip 协议节点通信(cluster.c)
void clusterSendPing(clusterNode *node) {
clusterMsg msg;
msg.type = CLUSTERMSG_TYPE_PING;
clusterSendMessage(node, &msg);
}
故障检测与恢复(cluster.c)
void clusterHandleFailover(clusterNode *node) {
if (node->flags & NODE_FAIL) {
promoteReplicaToMaster(node);
}
}
Keepalived:采用 VRRP 协议,提供高可用虚拟 IP。
Codis:引入 Proxy 层,屏蔽 Redis 迁移细节。
# 启动主节点
redis-server --port 6379 --protected-mode no
# 启动从节点
redis-server --port 6380 --protected-mode no
# 配置从节点复制主节点
redis-cli -p 6380 replicaof 127.0.0.1 6379
配置 sentinel.conf
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
启动Sentinel
redis-sentinel sentinel.conf
# 创建 6 个 Redis 实例
redis-server --port 7000 --cluster-enabled yes --cluster-config-file nodes-7000.conf --cluster-node-timeout 5000 --protected-mode no
...
# 创建 Redis 集群
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 ... --cluster-replicas 1
配置 keepalived.conf
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1234
}
virtual_ipaddress {
192.168.1.100
}
}
启动 Keepalived
systemctl start keepalived
Redis 高可用方案各有特点,应根据业务需求选择合适方案。小规模应用可采用主从复制+哨兵,中大型应用推荐集群模式,特定场景可结合 Keepalived 或 Codis。
希望本文能帮助你深入理解 Redis 高可用方案,欢迎留言交流!
开源一个纯AI生成的健身记录App,如需源码,可关注公众号:小健学Java,回复“健身”即可获得!
如需Java面试题资料,可关注公众号:小健学Java,回复“面试”即可获得!