RedisNotes

第 19 章:Cluster 原理

zjc 于 2026-01-19 发布

这是《Redis 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 当单实例内存、写入或网卡到达瓶颈,Redis Cluster 通过分片横向扩展。本章讲槽、key 分布、Gossip、MOVED/ASK、故障转移、扩缩容与限制。

19.1 Cluster 解决什么问题

单实例限制:

内存上限
CPU 写入上限
网卡吞吐
持久化 fork 时间
复制全量成本

Cluster 把数据按 key 分片到多个主节点:

Node A: slots 0-5460
Node B: slots 5461-10922
Node C: slots 10923-16383

每个主节点可以有从节点,主故障后从节点提升。

19.2 16384 个槽

计算:

CRC16(key) mod 16384

示例:

CLUSTER KEYSLOT user:1001
CLUSTER COUNTKEYSINSLOT 1234

槽是迁移和归属的最小单位。节点只负责自己的槽,不保存全量数据。

hash tag

order:{1001}:detail
order:{1001}:stock

只有 {} 中内容参与计算,两个 key 同槽,可执行多 key/Lua 操作。

风险:{hot-id} 会导致单槽热点,需避免所有请求集中同一 tag。

19.3 集群拓扑

Master A + Replica A'
Master B + Replica B'
Master C + Replica C'

节点间通过 cluster bus(默认 16379)Gossip 通信
业务端口默认 6379

最小生产建议:3 主 3 从。6 节点可部署在不同机器/可用区。

配置:

port 6379
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
cluster-require-full-coverage yes
cluster-replica-validity-factor 10
cluster-migration-barrier 1

19.4 创建集群

redis-cli --cluster create \
  10.0.0.11:6379 \
  10.0.0.12:6379 \
  10.0.0.13:6379 \
  10.0.0.14:6379 \
  10.0.0.15:6379 \
  10.0.0.16:6379 \
  --cluster-replicas 1

检查:

CLUSTER INFO
CLUSTER NODES
CLUSTER SLOTS
CLUSTER MYID

健康状态:

cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_known_nodes:6

19.5 请求路由:MOVED

客户端请求错误节点:

Client -> NodeB GET user:1001
NodeB -> MOVED 1234 NodeA:6379
Client -> NodeA GET user:1001

智能客户端会在本地缓存槽映射,并根据 MOVED 更新,稳定后一次直达正确节点。

非智能客户端每次都可能多一次 RTT,生产应使用支持 Cluster 的客户端。

19.6 请求路由:ASK

迁移槽时:

槽 1234 正在从 A 迁移到 B
Client 访问 A
A 本地无该 key -> ASK B
Client 先向 B 发 ASKING
B 允许执行本次请求

区别:

重定向 语义
MOVED 槽已归属新节点,客户端更新映射
ASK 槽正在迁移,只对本次请求临时转向

迁移完成后客户端才会收到 MOVED。

19.7 Gossip 协议

节点通过 cluster bus 交换:

作用:

  1. 发现拓扑;
  2. 传播故障标记;
  3. 传播配置纪元;
  4. 支持槽迁移与故障切换。

Gossip 是最终一致的,短时间内不同节点视图可能不同。

19.8 故障检测与转移

流程:

1. 节点 A 定期 PING 其他节点
2. 超过 cluster-node-timeout 未有效回复 -> PFAIL 疑似下线
3. 多数 Master 认为 A PFAIL -> 标记 FAIL
4. A 的 Replica 发起选举
5. 获得多数 Master 投票后提升为新 Master
6. 接管旧 Master 的槽

相关配置:

cluster-node-timeout 15000
cluster-replica-validity-factor 10
cluster-replica-no-failover no

cluster-require-full-coverage yes 表示任一槽不可用时集群拒绝相关请求;设为 no 可提升局部可用性,但需要业务明确接受。

19.9 多 key 操作限制

Cluster 中多 key 命令、事务、Lua 要求所有 key 同槽:

MSET user:1001 a user:2002 b
# 如果槽不同 -> CROSSSLOT

解决:

user:{1001}:profile
user:{1001}:score

或业务侧拆分请求,分别路由。

19.10 槽迁移与扩缩容

添加节点:

redis-cli --cluster add-node new-node:6379 old-node:6379

reshard:

redis-cli --cluster reshard any-node:6379

迁移过程:

1. 目标节点准备导入槽
2. 源节点标记迁移
3. 逐个 key 迁移
4. 迁移期间 ASK 重定向
5. 完成后槽归属更新并广播

检查:

redis-cli --cluster check node:6379
redis-cli --cluster fix node:6379

生产要点:

19.11 Cluster 的限制

  1. 多 key 操作必须同槽;
  2. DB 只建议使用 DB0;
  3. 槽迁移期间性能抖动;
  4. 客户端必须支持 Cluster 协议;
  5. 热点 key 仍落在单节点;
  6. 事务/Lua 复杂度受限;
  7. 集群不是自动数据均衡器,新增节点需 reshard;
  8. Pub/Sub 会广播到所有节点,带宽可能放大。

Sharded Pub/Sub 改善广播问题,但需要客户端与版本支持。

19.12 客户端配置

Spring Boot Lettuce:

spring:
  data:
    redis:
      cluster:
        nodes:
          - node1:6379
          - node2:6379
          - node3:6379
        max-redirects: 3
      timeout: 500ms

客户端要做:

本章小结

思考题

  1. 为什么 Redis Cluster 选择 16384 个槽而不是一致性哈希环?
  2. 如果某个热点商品 key 打满单节点,如何优化?
  3. Cluster 能否保证强一致?主从切换时会丢失数据吗?为什么?