Redis 集群方案
Redis 的高可用和高并发能力依赖于合理的集群架构设计。本文深入解析主从复制、哨兵模式和 Cluster 集群的原理与最佳实践。
一、Redis 集群架构演进
| 架构 | 特点 | 适用场景 | 数据分片 | 自动故障转移 |
|---|---|---|---|---|
| 单机 | 简单,但无高可用保障 | 开发/测试环境 | ❌ | ❌ |
| 主从复制 | 读写分离,手动故障转移 | 小规模,读多写少 | ❌ | ❌ |
| 哨兵模式 | 自动故障转移,监控主从状态 | 中等规模,需高可用 | ❌ | ✅ |
| Cluster | 数据分片,水平扩展,去中心化 | 大规模,高并发,需分片 | ✅ | ✅ |
二、主从复制 (Replication)
2.1 核心原理
主从复制: 将主节点(Master)的数据复制到从节点(Slave),实现读写分离。
1 | ┌─────────┐ 写操作 |
2.2 复制流程
第一阶段:建立连接
- 从节点执行
REPLICAOF <masterip> <masterport>(或配置replicaof)。 - 从节点与主节点建立 TCP 连接。
- 从节点发送
PING命令,主节点回复PONG(验证连通性)。
第二阶段:全量同步(Full Resync)
触发场景: 首次同步或从节点断线时间过长(增量缓冲区溢出)。
流程:
1 | 1. 从节点发送 PSYNC <runid> <offset> |
关键参数:
- runid: 主节点的唯一标识(每次重启会变化)。
- offset: 复制偏移量(标记同步进度)。
第三阶段:增量同步(Partial Resync)
触发场景: 从节点短暂断线重连。
流程:
1 | 1. 从节点发送 PSYNC <runid> <offset> |
复制积压缓冲区(repl-backlog):
- 环形缓冲区,默认 1MB。
- 存储最近的写命令,用于断线重连时的增量同步。
配置:
1 | repl-backlog-size 1mb # 缓冲区大小 |
第四阶段:命令传播(Command Propagation)
正常运行时: 主节点将每条写命令实时传播给所有从节点。
心跳机制:
- 从节点每秒发送一次
REPLCONF ACK <offset>(确认同步进度)。 - 主节点检测从节点是否在线(超时则标记为下线)。
2.3 主从复制配置
从节点配置
1 | # redis.conf(从节点) |
主节点配置
1 | # redis.conf(主节点) |
2.4 主从复制的问题
| 问题 | 影响 | 解决方案 |
|---|---|---|
| 主节点宕机 | 需手动切换,服务中断 | 使用哨兵模式 |
| 全量同步阻塞 | BGSAVE 导致性能抖动 | 使用 SSD、控制主节点数据量 |
| 从节点数量过多 | 主节点网络和 CPU 压力增大 | 使用级联复制(从-从结构) |
| 复制延迟 | 从节点数据可能过期 | 监控 info replication 中的 lag |
三、哨兵模式 (Sentinel)
3.1 核心功能
哨兵(Sentinel) 是 Redis 的高可用解决方案,提供以下功能:
- 监控(Monitoring): 检查主从节点是否正常工作。
- 通知(Notification): 通过 API 或脚本通知管理员。
- 自动故障转移(Automatic Failover): 主节点宕机时,自动选举新主节点。
- 配置中心: 客户端通过哨兵获取当前主节点地址。
3.2 架构设计
1 | ┌─────────────────────────────────────────┐ |
3.3 故障检测与选举
主观下线(Subjectively Down, SDOWN)
定义: 单个哨兵认为主节点下线(PING 超时)。
配置:
1 | # sentinel.conf |
客观下线(Objectively Down, ODOWN)
定义: 多数哨兵(quorum)认为主节点下线。
quorum 配置:
1 | sentinel monitor mymaster 192.168.1.100 6379 2 |
计算公式:
1 | quorum = 哨兵总数 / 2 + 1(推荐配置) |
选举新主节点(Leader Election)
流程:
1 | 1. 哨兵之间通过 Raft 协议选举出一个 Leader Sentinel |
3.4 哨兵配置详解
1 | # sentinel.conf |
3.5 哨兵模式的优缺点
| 优点 | 缺点 |
|---|---|
| 自动故障转移,无需人工干预 | 写能力受限于单个主节点 |
| 监控主从节点健康状态 | 不支持数据分片(无法水平扩展) |
| 客户端自动发现新主节点 | 配置复杂,运维成本高 |
| 高可用性(至少 3 个哨兵) | 哨兵本身需要高可用(至少 3 个) |
四、Redis Cluster (集群)
4.1 核心特性
Redis Cluster 是 Redis 官方的分布式解决方案,提供:
- 数据分片(Sharding): 数据自动分散到多个节点。
- 高可用(HA): 节点宕机自动故障转移。
- 去中心化: 无 Proxy 层,节点间直接通信。
- 线性扩展: 支持动态添加/删除节点。
4.2 哈希槽(Hash Slot)机制
核心概念: Redis Cluster 将数据空间划分为 16384 个哈希槽(0-16383)。
槽位分配
示例:3 主节点集群
1 | Master A:槽 0-5460 |
键到槽位的映射
计算公式:
1 | HASH_SLOT = CRC16(key) mod 16384 |
示例:
1 | key1 → CRC16("key1") = 12345 → 12345 % 16384 = 12345 → Master C |
Hash Tag(哈希标签)
作用: 强制多个 key 分配到同一槽位(支持多键操作)。
语法: {hashtag}key
示例:
1 | MSET {user:1000}:name "Alice" {user:1000}:age 25 |
4.3 节点间通信(Gossip 协议)
Gossip 协议: 节点间通过周期性的消息交换同步集群状态。
消息类型
| 消息类型 | 作用 |
|---|---|
MEET |
新节点加入集群 |
PING |
心跳检测(每秒随机向几个节点发送) |
PONG |
回复 PING |
FAIL |
标记节点下线 |
PUBLISH |
发布订阅消息 |
集群总线端口
端口: Redis 集群使用 Redis端口 + 10000 作为集群总线端口。
示例:
1 | 节点 1:6379(客户端)、16379(集群总线) |
4.4 故障检测与转移
主观下线(PFAIL)
定义: 节点 A 认为节点 B 下线(PING 超时)。
客观下线(FAIL)
定义: 多数主节点认为节点 B 下线。
流程:
1 | 1. 节点 A 发现节点 B 超时(PFAIL) |
4.5 搭建 Redis Cluster
最小配置(3 主 3 从)
1 | Master A (6379) ──┬── Slave A1 (6382) |
配置文件
1 | # redis-6379.conf |
创建集群
1 | redis-cli --cluster create \ |
参数说明:
--cluster-replicas 1:每个主节点有 1 个从节点。
4.6 集群扩容与缩容
扩容(添加节点)
1 | # 1. 启动新节点 |
缩容(删除节点)
1 | # 1. 迁移槽位到其他节点 |
4.7 客户端路由(MOVED 与 ASK)
MOVED 重定向
场景: 客户端访问错误节点。
流程:
1 | Client → Node A (槽 1234 不在此节点) |
ASK 重定向
场景: 槽位正在迁移中。
流程:
1 | Client → Node A (槽 1234 正在迁移到 Node B) |
4.8 Cluster 的限制
| 限制 | 说明 | 解决方案 |
|---|---|---|
| 不支持多键操作 | 如 MGET key1 key2(不同槽位) |
使用 Hash Tag |
| 不支持多数据库 | Cluster 模式只有 db0 |
业务层隔离 |
| 事务支持有限 | 事务中的 key 必须在同一槽位 | 使用 Hash Tag 或 Lua 脚本 |
| 不支持发布订阅的跨节点 | PUBLISH 只在当前节点生效 |
使用消息队列(Kafka、RabbitMQ) |
| 从节点不参与读操作(默认) | 从节点仅用于高可用 | 开启 READONLY 模式 |
4.9 Cluster vs 哨兵对比
| 特性 | 哨兵模式 | Cluster |
|---|---|---|
| 数据分片 | ❌(单主节点,写能力受限) | ✅(16384 个槽位,水平扩展) |
| 自动故障转移 | ✅ | ✅ |
| 配置复杂度 | 中等 | 高 |
| 客户端支持 | 需哨兵感知客户端 | 需集群感知客户端(如 Jedis、Lettuce) |
| 适用场景 | 中等规模,读多写少 | 大规模,高并发,需分片 |
五、集群选型建议
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 小规模,读多写少 | 主从复制 + 哨兵 | 简单,成本低 |
| 中等规模,需高可用 | 哨兵模式 | 自动故障转移,配置相对简单 |
| 大规模,高并发,需分片 | Redis Cluster | 水平扩展,数据分片,去中心化 |
| 超大规模(TB 级数据) | Cluster + Proxy | Twemproxy/Codis 实现分片路由 |
| 多云/混合云部署 | 哨兵 + VIP | VIP 漂移实现跨机房故障转移 |
六、面试高频问题
主从复制的全量同步和增量同步有什么区别?
- 全量同步:RDB + backlog;增量同步:仅发送断线期间的命令。
哨兵是如何选举出新主节点的?
- Raft 协议选举 Leader Sentinel,再根据优先级、offset、runid 选出新主节点。
Redis Cluster 如何实现数据分片?
- 通过 CRC16(key) % 16384 计算槽位,每个节点负责一部分槽位。
Cluster 的 MOVED 和 ASK 重定向有什么区别?
- MOVED:槽位固定不在此节点;ASK:槽位正在迁移中。
如何解决 Cluster 的多键操作限制?
- 使用 Hash Tag 强制多个 key 在同一槽位。
为什么哨兵至少需要 3 个?
- 保证 quorum(多数派)有效,避免脑裂。
Cluster 如何保证高可用?
- 每个主节点有从节点,主节点宕机时自动故障转移。
通过合理的集群架构设计,Redis 可以支撑亿级流量和 PB 级数据!🚀
