Redis 集群方案
问题
Redis 的三种集群方案是什么?Cluster 的哈希槽原理是什么?如何选择集群方案?
答案
一、三种方案概览
| 方案 | 解决的问题 | 特点 |
|---|---|---|
| 主从复制 | 数据备份、读扩展 | 手动故障转移 |
| Sentinel 哨兵 | 自动故障转移 | 主从 + 监控 + 自动切换 |
| Cluster | 数据分片 + 高可用 | 分布式存储,扩展写能力 |
二、主从复制
复制过程
-
全量同步(首次连接):
- 从库发送 PSYNC 命令
- 主库 BGSAVE 生成 RDB 文件,发送给从库
- 从库清空数据,加载 RDB
- 主库将这期间的写命令发送给从库
-
增量同步(断线重连):
- 主库维护复制积压缓冲区(repl_backlog)
- 从库通过 offset 请求缺失的数据
- 如果 offset 还在缓冲区内 → 增量同步
- 如果 offset 已被覆盖 → 退化为全量同步
三、Sentinel 哨兵
故障转移流程
选择新主库的规则(按优先级):
- 排除不健康的从库
- 优先级最高(
slave-priority最小) - 复制偏移量最大(数据最新)
- run_id 最小
四、Redis Cluster
Redis Cluster 是官方的分布式方案,支持 数据分片 + 高可用。
哈希槽(Hash Slot)
Redis Cluster 将数据划分为 16384 个哈希槽:
slot = CRC16(key) % 16384
每个节点负责一部分槽。扩容时只需迁移部分槽到新节点。
为什么是 16384 个槽?
Redis 作者的回答:
- 正常集群不超过 1000 个节点
- 16384 个槽的位图只需 2KB,节点间心跳包可以带上
- 65536 个槽需要 8KB,心跳包太大
Cluster 架构
请求路由
客户端请求任意节点:
- 如果 key 在当前节点 → 直接处理
- 如果 key 不在当前节点 → 返回
MOVED重定向
客户端 → Node A: GET user:100
Node A → 客户端: MOVED 12345 Node C(说明 slot 12345 在 Node C)
客户端 → Node C: GET user:100
Node C → 客户端: "张三"
五、方案选型
| 场景 | 推荐方案 | 说明 |
|---|---|---|
| 数据量小,需要高可用 | Sentinel | 简单够用 |
| 数据量大,需要扩展 | Cluster | 官方分布式 |
| 只需读扩展 | 主从复制 | 最简单 |
| 缓存场景,允许少量丢失 | Sentinel / Cluster | 视数据量 |
| 持久化存储 | Cluster + AOF | 数据分片 + 持久化 |
常见面试问题
Q1: Redis Cluster 为什么不用一致性哈希?
答案:
Redis Cluster 使用预分配哈希槽(而非一致性哈希环)的原因:
- 哈希槽方案更简单,CRC16 取模即可
- 数据迁移以槽为单位,更可控
- 不需要虚拟节点来解决数据倾斜
- 节点增减时,只需要迁移特定槽的数据
Q2: Cluster 模式下,多 key 操作有什么限制?
答案:
Redis Cluster 要求多 key 操作(MGET、事务、Lua脚本)的所有 key 必须在 同一个槽 中。
解决方案:使用 Hash Tag,将相关的 key 放入同一槽:
# {user:100} 是 Hash Tag,只对 {} 内的部分计算 slot
SET {user:100}:name "张三"
SET {user:100}:age 25
MGET {user:100}:name {user:100}:age # 同一个 slot,可以执行
Q3: Sentinel 和 Cluster 可以混用吗?
答案:
不需要。Redis Cluster 内置了故障检测和自动转移功能(通过 Gossip 协议),不需要额外的 Sentinel。Sentinel 适用于非 Cluster 的主从架构。