谈谈 Redis 集群模式?

#中间件#面试八股

谈谈 Redis 集群模式?

结论:Redis 的集群能力演进是三步:主从复制解决读扩展与数据备份,哨兵解决主节点故障自动切换,Cluster 解决水平分片与容量扩展。三者不是替代关系,Cluster 的每个分片内部依然是一主多从。选型看两点:单机能装下就"主从 + 哨兵",装不下或单节点写入打满才上 Cluster;不想改客户端就用代理层方案。

一、三种模式对照

维度主从复制哨兵(Sentinel)Cluster
解决的问题读扩展、数据冗余自动故障转移分片 + 高可用
数据分布全量复制,每节点都有全量同主从16384 槽分散到多个主节点
写能力单主,不可扩展单主多主并行,可扩展
故障转移手动哨兵自动选举集群内部自动 failover
客户端复杂度低中(需连哨兵发现主)中(需处理 MOVED/ASK)
跨 key 操作无限制无限制必须在同一槽
最小规模1 主 1 从3 哨兵 + 1 主 1 从3 主 3 从

二、Cluster 的分片与路由

              ┌─────────────────────────────────────────────┐
              │              Cluster(16384 slots)           │
              └───────┬──────────────┬──────────────┬───────┘
                      │              │              │
              ┌───────▼──────┐ ┌─────▼────────┐ ┌───▼──────────┐
              │ 主A slot     │ │ 主B slot     │ │ 主C slot     │
              │ 0-5460       │ │ 5461-10922   │ │ 10923-16383  │
              └───────┬──────┘ └─────┬────────┘ └───┬──────────┘
                      │              │              │
              ┌───────▼──────┐ ┌─────▼────────┐ ┌───▼──────────┐
              │ 从A'          │ │ 从B'          │ │ 从C'          │
              └──────────────┘ └──────────────┘ └──────────────┘

路由:slot = CRC16(key) % 16384
  ├─ 客户端已缓存槽映射 → 直接连对应节点
  └─ 槽已迁移 → 节点返回 MOVED(永久迁移)或 ASK(临时迁移)

为什么是 16384 个槽而不是 65536?槽位图用位图表示,16384 个槽只占 2 KB,节点间 gossip 心跳要频繁携带槽位图,65536 会占 8 KB,心跳包与带宽开销翻四倍;而集群规模一般不超过 1000 个节点,16384 已经足够分散。

三、命令与配置

# 开启集群模式
redis-server --cluster-enabled yes --cluster-config-file nodes.conf \
             --cluster-node-timeout 15000 --appendonly yes

# 创建 3 主 3 从(--cluster-replicas 1)
redis-cli --cluster create 10.0.0.1:6379 10.0.0.2:6379 10.0.0.3:6379 \
          10.0.0.4:6379 10.0.0.5:6379 10.0.0.6:6379 --cluster-replicas 1

# 查看与运维
redis-cli -c -h 10.0.0.1 -p 6379 CLUSTER INFO
redis-cli -c CLUSTER NODES
redis-cli --cluster check 10.0.0.1:6379
redis-cli --cluster reshard 10.0.0.1:6379      # 在线迁移槽
redis-cli --cluster add-node 10.0.0.7:6379 10.0.0.1:6379
# 集群相关配置
cluster-enabled yes
cluster-node-timeout 15000
cluster-require-full-coverage no    # 有槽不可用时是否拒绝整个集群写入
cluster-allow-reads-when-down no    # 集群不可用时是否允许读
cluster-migration-barrier 1

四、常见追问

  • 问:cluster-require-full-coverage yes 有什么风险?答:任意一个槽不可用(某主节点及其从节点全挂)整个集群就拒绝所有写入,可用性极差;通常设为 no,让未受影响的槽继续服务。
  • 问:MOVED 和 ASK 的区别?答:MOVED 表示槽已永久迁到新节点,客户端应更新本地槽缓存;ASK 表示槽正在迁移中,本次请求临时去目标节点,客户端不更新缓存。
  • 问:为什么跨 key 命令在 Cluster 下会失败?答:不同 key 可能落在不同槽、不同节点,MGET/MSET/事务/Lua 无法保证原子与一致性,Redis 直接返回 CROSSSLOT。用 hash tag {user:1} 把相关 key 固定到同一槽。
  • 问:Cluster 下还能用 Lua 吗?答:能,但脚本里的所有 key 必须同槽;KEYS 与 ARGV 的构造要保证这一点。
  • 问:哨兵和 Cluster 怎么选?答:数据量小于单机内存、写入不瓶颈 → 主从 + 哨兵,运维简单;需要水平扩容或单主写入打满 → Cluster。
  • 问:Cluster 的故障转移靠什么判定?答:节点间 gossip + cluster-node-timeout,多数主节点认为某主不可达后,由其从节点发起选举,获得多数票后晋升。

小结

  • 主从管复制、哨兵管切换、Cluster 管分片,能力逐层叠加而非互斥。
  • Cluster 的心智负担集中在"槽":路由、迁移、同槽限制、全槽可用性开关。
  • 选型先看容量与写入是否超出单机,再评估客户端与运维是否能接受 Cluster 的限制。
笔记加载中…