Redis 集群方案
Redis 的集群方案经历了从主从复制 → 哨兵模式 → Redis Cluster → Codis 的演进,每种方案解决了不同阶段的问题。
主从复制(Replication)
架构
text
┌─────────┐
│ Master │ ← 可读可写(单点)
└────┬─────┘
│ 复制数据
┌───────┼────────┐
│ │ │
┌───┴──┐ ┌──┴───┐ ┌──┴───┐
│ Slave│ │Slave │ │Slave │ ← 只读,异步复制
└──────┘ └──────┘ └──────┘复制原理
text
Slave 启动:
1. 向 Master 发送 SYNC(旧版)或 PSYNC(2.8+)
2. Master 执行 BGSAVE 生成 RDB
3. Master 将 RDB 发送给 Slave
4. Slave 加载 RDB → 数据与 Master 一致
5. 后续增量复制:Master 将写命令推入复制缓冲区
PSYNC 断线重连:
- Master 维护复制积压缓冲区(repl_backlog)
- Slave 发送 offset + runid → 增量同步
- 如果 offset 已不在缓冲区 → 全量重同步优缺点
| 优点 | 缺点 |
|---|---|
| 读写分离,分摊读压力 | 主节点宕机需手动切换 |
| 数据热备份 | 异步复制可能丢数据 |
| 简单易部署 | 无自动故障转移 |
哨兵模式(Sentinel)
架构
text
┌────────────┐
│ Sentinel │ ← 哨兵集群(至少 3 个)
└─────┬──────┘
│ 监控 + 选举 + 通知
┌──────────┼──────────┐
│ │ │
┌───┴────┐ ┌──┴────┐ ┌──┴────┐
│ Master │ │Slave 1│ │Slave 2│
└────────┘ └───────┘ └───────┘工作原理
监控:Sentinel 每 1 秒 ping 所有节点,down-after-milliseconds 判定主观下线。
主观下线 → 客观下线:
- 主观下线(SDOWN):单个 Sentinel 认为节点不可达
- 客观下线(ODOWN):多个 Sentinel(quorum)认为 Master 不可达
故障转移:
text
1. Sentinel 选举 Leader(Raft 算法)
2. Sentinel Leader 执行故障转移:
a. 从 Slave 中选一个新 Master
b. 向其他 Slave 发送 SLAVEOF 新 Master
c. 原 Master 恢复后降级为 Slave选举策略(优先级从高到低):
- 优先级
slave-priority最高 - 复制偏移量最大(数据最新)
- runId 最小
哨兵数量建议
| Sentinel 数量 | quorum | 容错数 | 说明 |
|---|---|---|---|
| 1 | 1 | 0 | 部署单点 |
| 3 | 2 | 1 | 最小推荐部署 |
| 5 | 3 | 2 | 更高可用性 |
优缺点
| 优点 | 缺点 |
|---|---|
| 自动故障转移 | 写能力无扩展(单 Master) |
| 主从切换对外透明 | 大流量场景写成为瓶颈 |
| 部署相对简单 | 存储容量受单机限制 |
Redis Cluster(官方集群)
架构
Redis 3.0+ 推出的官方分布式方案,采用无中心化架构。
text
┌───────────┐
│ Cluster │ ← Gossip 协议通信
│ 16384 槽 │
└─────┬─────┘
┌────────┼────────┐
│ │ │
┌───┴────┐ ┌┴──────┐ ┌┴──────┐
│ Node 1 │ │Node 2 │ │Node 3 │
│ 槽 0-5500│ │槽 5501-11000│ │槽 11001-16383│
│ Master │ │Master │ │Master │
│ Slave │ │Slave │ │Slave │
└────────┘ └───────┘ └───────┘数据分片
CRC16 哈希槽:
text
slot = CRC16(key) % 16384虚拟槽优势:
- 均匀分布数据
- 方便扩缩容(迁移槽即可)
- 客户端直连任意节点获取路由信息
节点通信(Gossip)
text
每个节点维护集群元数据,每秒通过 Gossip 交换:
- 节点状态(在线/下线)
- 槽分配信息
- Ping/Pong 消息
带宽公式 ≈ 1 秒 × 节点数 × 消息体
大集群中可通过 cluster-node-timeout 降低通信频率请求路由
text
客户端连接任一节点:
1. MOVED 重定向
GET key → Node 1 检查 slot 不在本节点
→ 返回 MOVED 4789 192.168.1.2:6379
→ 客户端缓存路由,下次直连
2. ASK 重定向(迁移中)
GET key → 返回 ASK 4789 192.168.1.2:6379
→ 客户端先发送 ASKING 再执行命令高可用
- 每个 Master 可挂载 1 个或多个 Slave
- Master 宕机,Slave 自动晋升
- 集群分区后,存活节点数 < 总 Master 一半时集群不可用
优缺点
| 优点 | 缺点 |
|---|---|
| 线性扩展读写能力 | 只支持 1 个 database(db0) |
| 自动故障转移 | 批量操作需 key 在同一槽(hash tag) |
| 无中心化 | 事务支持有限 |
| 官方维护 | 跨节点操作需客户端处理 |
hash tag
text
// 使用 {} 强制 key 映射到同一槽
user:{1001}:profile
user:{1001}:orders
// 上述两个 key 的 {} 部分相同 → 同一节点 → 支持事务Codis(Proxy 方案)
Codis 是豌豆荚开源的 Redis 分布式方案(3.x 后开源),采用 Proxy 层路由。
架构
text
┌──────────┐
│ Client │
└─────┬────┘
│ 看起来像单机 Redis
┌─────────┼─────────┐
│ │ │
┌───┴───┐ ┌───┴───┐ ┌───┴───┐
│ Codis │ │ Codis │ │ Codis │ ← Proxy 层(无状态)
│ Proxy │ │ Proxy │ │ Proxy │
└───┬───┘ └───┬───┘ └───┬───┘
└────┬────┘ ┌────┘
│ │
┌────┴─────────┴────┐
│ ZooKeeper │ ← 配置中心
└────────┬─────────┘
│
┌────────────┼────────────┐
│ │ │
┌───┴────┐ ┌───┴────┐ ┌───┴────┐
│Redis SG│ │Redis SG│ │Redis SG│ ← 每组主从
└────────┘ └────────┘ └────────┘分片方式
Codis 使用 Pre-Sharding(预分片):将 1024 个槽预先分配给所有 redis-server 组。
优缺点
| 优点 | 缺点 |
|---|---|
| 客户端无需改造(兼容 Redis 协议) | 多一层 Proxy 增加延迟(约 0.5ms) |
| 支持在线扩缩容 | 不再活跃维护(建议优先使用 Cluster) |
| 支持 pipeline 和事务 | 相比 Cluster 更重 |
方案对比
| 特性 | 主从复制 | 哨兵模式 | Redis Cluster | Codis |
|---|---|---|---|---|
| 写扩展 | ❌ | ❌ | ✅ | ✅ |
| 读扩展 | ✅(从节点) | ✅(从节点) | ✅ | ✅ |
| 自动故障转移 | ❌ 手动 | ✅ | ✅ | ✅ |
| 数据分片 | ❌ | ❌ | ✅(16384 槽) | ✅(1024 槽) |
| 客户端兼容 | 原生 | 原生 | MOVED 重定向 | 透明代理 |
| 部署复杂度 | ⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 延迟 | 极低 | 极低 | 低 | 中(+0.5ms) |
| 节点数 | 2~N | 3~N | ≥6(3主3从) | ≥6 |
选型建议
text
单机 Redis → 主从 + 哨兵 → Redis Cluster
数据量 < 10G 可用性优先 容量 > 100G
可用性要求低 写 QPS < 1万 水平扩展- 主从 + 哨兵:适合读多写少、数据量可控的场景
- Redis Cluster:适合大数据量、需要水平扩展的场景
- Codis:遗留系统或客户端无法改造时的备选