Redis Cluster vs Codis vs Twemproxy vs 主从+哨兵对比
面试官:「你们项目用的是什么 Redis 集群方案?」
你:「用的主从 + Sentinel。」
面试官:「为什么不用 Cluster?」
你:「……」
今天来聊聊 Redis 分布式架构的各种方案,以及如何选择。
方案概览
| 方案 | 数据分片 | 高可用 | 代理 | 复杂度 | 适用规模 |
|---|---|---|---|---|---|
| 主从 + Sentinel | 无 | 有 | 无 | 低 | < 10 万 QPS |
| Codis | 有 | 有 | 有 | 中 | < 100 万 QPS |
| Twemproxy | 有 | 无 | 有 | 低 | < 50 万 QPS |
| Redis Cluster | 有 | 有 | 无 | 中 | < 100 万 QPS |
| Redis 自建多实例 | 手动 | 自研 | 自研 | 高 | 按需 |
方案一:主从 + Sentinel
架构
┌─────────────────────────────────────────────────────────────────┐
│ 主从 + Sentinel 架构 │
│ │
│ ┌───────────────┐ │
│ │ Sentinel │ │
│ │ (哨兵集群) │ │
│ └───────┬───────┘ │
│ │ │
│ ┌───────▼───────┐ │
│ │ 主节点 │ │
│ └───────┬───────┘ │
│ │ 复制 │
│ ┌───────────┼───────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 从节点1 │ │ 从节点2 │ │ 从节点3 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ 客户端通过 Sentinel 获取主节点地址 │
│ │
└─────────────────────────────────────────────────────────────────┘特点
| 特性 | 说明 |
|---|---|
| 优点 | 架构简单、配置简单、故障自动切换 |
| 缺点 | 无法水平扩展、主节点写入能力受限 |
| 适用场景 | 小规模部署、读多写少、数据量有限 |
配置示例
bash
# 主节点配置
bind 0.0.0.0
port 6379
daemonize yes
# 从节点配置
replicaof 127.0.0.1 6379
replica-serve-stale-data yes
# Sentinel 配置
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000适用规模
- QPS:< 10 万(受主节点限制)
- 数据量:< 100GB(受单机内存限制)
- 节点数:通常 1 主 2 从
方案二:Codis
架构
┌─────────────────────────────────────────────────────────────────┐
│ Codis 架构 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Codis │ │ Codis │ │ Codis │ │
│ │ Proxy 1 │ │ Proxy 2 │ │ Proxy 3 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └───────────────┼───────────────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ Zookeeper │ │
│ │ (配置中心) │ │
│ └─────────┬─────────┘ │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Redis │ │ Redis │ │ Redis │ │
│ │ Master1 │ │ Master2 │ │ Master3 │ │
│ │(Slot 0-400)│ │(Slot 400-800)│ │(Slot 800-1024)│ │
│ └───┬─────┘ └───┬─────┘ └───┬─────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Slave1 │ │ Slave2 │ │ Slave3 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘特点
| 特性 | 说明 |
|---|---|
| 优点 | 支持数据分片、自动迁移、对客户端友好 |
| 缺点 | 需要 ZooKeeper、代理有性能损耗、代码停更 |
| 适用场景 | 中大规模、需要平滑扩容 |
Codis vs Redis Cluster
| 维度 | Codis | Redis Cluster |
|---|---|---|
| 分片方式 | Proxy 计算槽 | 客户端/代理计算槽 |
| 配置中心 | ZooKeeper | 无(Gossip 协议) |
| 槽迁移 | 官方支持 | 官方支持 |
| 代理 | Codis Proxy | 无(可有Twemproxy) |
| 维护状态 | 停更(2016) | 活跃维护 |
| 客户端兼容 | 任意 Redis 客户端 | 需支持 Cluster |
Codis 配置
yaml
# codis.json
{
"zk": "127.0.0.1:2181",
"product": "codis-demo",
"proxy_id": "proxy_1",
"io_thread_num": 8,
"worker_num": 8
}方案三:Twemproxy
架构
┌─────────────────────────────────────────────────────────────────┐
│ Twemproxy 架构 │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ Twemproxy│ │ Twemproxy│ │
│ │ Proxy1 │ │ Proxy2 │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ └───────────────┼────────────────────────────────────── │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Redis │ │ Redis │ │ Redis │ │
│ │ Server1 │ │ Server2 │ │ Server3 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘特点
| 特性 | 说明 |
|---|---|
| 优点 | 轻量、配置简单、支持多种哈希算法 |
| 缺点 | 不支持高可用(无故障转移)、不支持动态扩容 |
| 适用场景 | 简单分片需求、作为过渡方案 |
Twemproxy 配置
yaml
# nutcracker.yml
redis1:
listen: 127.0.0.1:6379
hash: fnv1a_64
distribution: ketama
servers:
- 127.0.0.1:6380:1
- 127.0.0.1:6381:1
- 127.0.0.1:6382:1方案四:Redis Cluster
架构
┌─────────────────────────────────────────────────────────────────┐
│ Redis Cluster 架构 │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Master1 │ │ Master2 │ │ Master3 │ │
│ │ (槽0-5460)│ │(槽5461-10922)│ (槽10923-16383)│ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ │ │ │ │
│ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │
│ │ Slave1 │ │ Slave2 │ │ Slave3 │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ 所有节点通过 Gossip 协议互联 │
│ 客户端直连任意节点 │
│ │
└─────────────────────────────────────────────────────────────────┘特点
| 特性 | 说明 |
|---|---|
| 优点 | 原生支持、去中心化、自动故障转移、在线扩容 |
| 缺点 | 不支持跨槽操作、客户端需要支持 Cluster、复杂度高 |
| 适用场景 | 大规模部署、需要平滑扩容 |
方案对比表
| 维度 | 主从+Sentinel | Codis | Twemproxy | Redis Cluster |
|---|---|---|---|---|
| 数据分片 | 无 | 有 | 有 | 有 |
| 高可用 | 有 | 有 | 无 | 有 |
| 自动故障转移 | 有 | 有 | 无 | 有 |
| 在线扩容 | 无 | 有 | 无 | 有 |
| 代理 | 无 | Codis Proxy | Twemproxy | 无 |
| 配置中心 | Sentinel | ZooKeeper | 无 | 无 |
| 运维复杂度 | 低 | 中 | 低 | 中 |
| 客户端兼容性 | 好 | 好 | 好 | 一般 |
| 多 key 操作 | 支持 | 支持 | 支持 | 限制 |
| 社区活跃度 | 高 | 低 | 低 | 高 |
如何选择?
选择决策树
你的需求是什么?
│
├─ 小规模(< 10 万 QPS,< 100GB)?
│ └─→ 主从 + Sentinel
│
├─ 需要水平扩展,但不想引入太多复杂度?
│ └─→ Redis Cluster
│
├─ 使用 Java/Go 客户端,需要完整 Redis 命令支持?
│ └─→ Codis(如果能接受停更)
│
└─ 简单分片,不需要高可用?
└─→ Twemproxy场景分析
场景一:创业公司,小规模部署
推荐:主从 + Sentinel
理由:
- 架构简单,运维成本低
- 初期数据量和 QPS 都不会太高
- 故障自动切换,保证可用性
场景二:中型公司,需要平滑扩容
推荐:Redis Cluster
理由:
- 支持在线扩容,数据自动迁移
- 原生支持,社区活跃
- 不需要额外依赖(ZooKeeper)
场景三:需要完整 Redis 语义
推荐:Codis
理由:
- 代理计算槽,客户端无需适配
- 支持所有 Redis 命令
- 支持跨槽操作(通过 Proxy 处理)
场景四:简单缓存分片
推荐:Twemproxy
理由:
- 轻量级,配置简单
- 满足基本分片需求
- 不需要高可用时足够用
Java 客户端选择
| 客户端 | 支持 Cluster | 支持 Sentinel | 特点 |
|---|---|---|---|
| Jedis | 是 | 是 | 广泛使用 |
| Lettuce | 是 | 是 | 响应式、支持连接池 |
| Redisson | 是 | 是 | 丰富的分布式数据结构 |
java
// Jedis 连接 Sentinel
JedisSentinelPool pool = new JedisSentinelPool(
"mymaster", sentinels, poolConfig
);
// Jedis 连接 Cluster
JedisCluster cluster = new JedisCluster(
new HostAndPort("127.0.0.1", 7000),
poolConfig
);
// Lettuce 连接 Cluster(Spring Boot 默认)
RedisClusterClient client = RedisClusterClient.create(
RedisURI.create("redis://127.0.0.1:7000")
);
StatefulRedisClusterConnection conn = client.connect();总结
| 方案 | 适用场景 | 不适用场景 |
|---|---|---|
| 主从+Sentinel | 小规模、高可用 | 水平扩展 |
| Redis Cluster | 中大规模、需扩容 | 多 key 跨槽 |
| Codis | 完整 Redis 语义 | 不接受停更 |
| Twemproxy | 简单缓存分片 | 需要高可用 |
留给你的问题
假设你的业务使用 Redis Cluster 存储用户 Session。
问题:用户登录后,其 Session 数据(key = session:{userId})被路由到了 Node A。一段时间后,Node A 宕机,这个用户的 Session 数据会丢失吗?Cluster 是如何保证 Session 可用的?
