Redis 集群方案
问题
Redis 的高可用方案有哪些?主从复制、哨兵和 Cluster 的区别是什么?Redis Cluster 如何实现数据分片?
答案
Redis 部署架构演进
主从复制
一主多从,主写从读,通过 binlog 同步。
同步流程
| 阶段 | 说明 |
|---|---|
| 全量同步 | 从节点首次连接:主节点 BGSAVE 生成 RDB → 发送给从节点 → 从节点加载 RDB → 期间的增量命令通过 buffer 补发 |
| 增量同步 | 正常运行时:主节点将写命令传播到从节点(命令传播) |
| 部分重同步 | 从节点断线重连:通过 repl_backlog 缓冲区只同步断线期间的命令(2.8+) |
# 从节点 redis.conf
replicaof 192.168.1.100 6379
主从复制的问题
- 主节点故障需手动切换
- 只解决了读扩展,写能力受限于单主
- 不提供自动故障转移
哨兵模式(Sentinel)
哨兵是 Redis 高可用的解决方案,通过监控主从节点,自动完成故障转移。
故障转移流程
- 主观下线:单个 Sentinel 认为主节点不可达(ping 超时)
- 客观下线:超过
quorum数量的 Sentinel 都认为主节点不可达 - Leader 选举:Sentinel 之间通过 Raft 选出一个 Leader 执行故障转移
- 选新主:从存活的从节点中按优先级、复制偏移量、ID 选出新主
- 切换:通知其他从节点复制新主,通知客户端连接新主
# sentinel.conf
sentinel monitor mymaster 192.168.1.100 6379 2 # quorum=2
sentinel down-after-milliseconds mymaster 5000 # 5 秒无响应判定下线
sentinel failover-timeout mymaster 60000 # 故障转移超时 60 秒
哨兵的局限
- 写能力仍受限于单主
- 存储容量受限于单机内存
- 故障转移期间有短暂不可用时间
Redis Cluster
Redis 官方的分布式方案,支持数据分片 + 高可用 + 自动故障转移。
哈希槽(Hash Slot)
Redis Cluster 将数据划分为 16384 个哈希槽,分配给各主节点:
slot = CRC16(key) % 16384
| 特性 | 说明 |
|---|---|
| 槽总数 | 16384 |
| 分配方式 | 平均分配或手动指定 |
| 槽迁移 | 支持在线迁移(不停机扩缩容) |
节点间通过 Gossip 协议交换槽位信息,每个节点发送的心跳包包含一个 16384 位的 bitmap(2KB)。如果用更多的槽,bitmap 更大,增加网络开销。16384 是一个在集群规模(一般不超过 1000 个节点)和网络开销之间的均衡选择。
MOVED 重定向
客户端发送命令到错误节点时,会收到 MOVED 响应:
-> GET key1
-MOVED 12345 192.168.1.102:6379
客户端应更新本地的槽-节点映射表,下次直接请求正确节点。
节点通信
Redis Cluster 使用 Gossip 协议 进行节点间通信:
| 消息类型 | 说明 |
|---|---|
| PING | 检测节点是否在线 |
| PONG | 回复 PING |
| MEET | 邀请新节点加入集群 |
| FAIL | 通知其他节点某节点已下线 |
Cluster 故障转移
与哨兵类似,但由 Cluster 节点自身完成:
- 从节点检测到主节点下线
- 从节点发起投票请求
- 集群中过半主节点同意
- 从节点晋升为主节点,接管槽位
三种方案对比
| 对比维度 | 主从复制 | 哨兵 | Cluster |
|---|---|---|---|
| 高可用 | ❌ 手动切换 | ✅ 自动故障转移 | ✅ 自动故障转移 |
| 数据分片 | ❌ | ❌ | ✅ 16384 哈希槽 |
| 写扩展 | ❌ 单主 | ❌ 单主 | ✅ 多主 |
| 存储扩展 | ❌ 单机 | ❌ 单机 | ✅ 多机 |
| 复杂度 | 低 | 中 | 高 |
| 适用场景 | 读多写少、开发测试 | 中小规模高可用 | 大规模、高并发 |
常见面试问题
Q1: Redis Cluster 的数据分片原理?
答案:
Redis Cluster 使用哈希槽(Hash Slot) 进行数据分片:
- 共 16384 个槽,分配给集群中的各主节点
- 每个 key 通过
CRC16(key) % 16384计算所属槽 - 客户端根据槽映射表将请求发到对应节点
- 如果发错了,节点返回
MOVED重定向
扩容时通过在线槽迁移,将部分槽从旧节点迁移到新节点,无需停机。
Q2: 哨兵如何判断主节点下线?
答案:
分为两个阶段:
- 主观下线(SDOWN):单个 Sentinel 在
down-after-milliseconds时间内未收到主节点的有效回复,认为该节点主观下线 - 客观下线(ODOWN):该 Sentinel 询问其他 Sentinel,当有
quorum数量的 Sentinel 都认为主节点下线,则判定为客观下线,触发故障转移
quorum 的建议值为 Sentinel 总数 / 2 + 1(如 3 个 Sentinel 的 quorum 设为 2)。
Q3: Cluster 模式下多 key 操作有什么限制?
答案:
Redis Cluster 不支持跨槽的多 key 操作。MGET、MSET、PIPELINE 中包含的 key 如果分布在不同槽,会报错。
解决方案:
- Hash Tag:使用
{tag}让相关 key 计算到同一个槽
# {user:1} 是 Hash Tag,这两个 key 会在同一个槽
SET {user:1}:name "张三"
SET {user:1}:age 25
MGET {user:1}:name {user:1}:age # ✅ 同槽,可以
- 客户端分组:按槽对 key 分组,分别发送请求后合并结果
Q4: 主从复制的全量同步和增量同步?
答案:
- 全量同步(首次连接或 backlog 丢失):主节点执行 BGSAVE 生成 RDB → 发送 RDB 给从节点 → 从节点清空数据加载 RDB → 主节点将 RDB 期间的增量命令发送给从节点
- 增量同步(正常运行时):主节点将写命令通过 TCP 连接传播给从节点
- 部分重同步(断线重连):从节点携带
replication offset,如果偏移量在主节点的repl_backlog中,只补发缺失部分;否则触发全量同步
Q5: Redis Cluster 为什么至少需要 6 个节点?
答案:
Redis Cluster 要求至少 3 个主节点(故障转移投票需要过半主节点同意),每个主节点至少 1 个从节点(保证主节点故障后有从节点接管),所以最小配置是 3 主 3 从 = 6 节点。
如果只有 2 个主节点,一个主节点挂了,另一个无法达到"过半"的投票条件,集群将不可用。