Redis 系列(十一):高可用(二)——Redis Cluster 集群

核心目标:理解 16384 个哈希槽的分片原理、gossip 通信与 MOVED/ASK 重定向;能搭建三主三从集群;理解集群模式的功能限制(CROSSSLOT、db0 only、多 key 命令);能评估"哨兵 + 主从"与"集群"的选型。

前置知识 :完成 Part 10(复制与故障转移------集群分片内仍依赖这些机制)。

验证环境 :Redis 8.10.0(cygwin 移植版);三主三从共 6 个隔离实例(6380-6385),redis-cli --cluster 创建。最后复核日期:2026-08-07。


0. 本篇问题场景:单主库的天花板

哨兵解决了"主库挂了自动切换",但仍有三个上限:

  1. 写容量:所有写都打在一个主库,单线程 CPU 饱和后加机器没用;
  2. 内存容量:数据总量受单机内存限制,换大内存机器有成本上限;
  3. 故障半径:一次主库宕机,整个数据集不可写。

Redis Cluster 的答案:分片------把 16384 个哈希槽摊到多个主节点,每个主节点只服务自己那部分槽。写能力、内存容量、故障半径随之分摊。


1. 分片模型:16384 个哈希槽

1.1 槽的分配

text 复制代码
CLUSTER KEYSLOT order:1001     → slot 241      (节点 A)
CLUSTER KEYSLOT user:42        → slot 15880    (节点 C)
CLUSTER KEYSLOT product:9      → slot 264      (节点 A)

本实验三主节点分片(redis-cli --cluster create 自动分配):

text 复制代码
127.0.0.1:6380  master  slots:[0-5460]
127.0.0.1:6381  master  slots:[5461-10922]
127.0.0.1:6382  master  slots:[10923-16383]
+ 6383/6384/6385 分别为三个主的从库

cluster info 的健康指标:

text 复制代码
cluster_state:ok
cluster_slots_assigned:16384    ← 槽全部有归属
cluster_known_nodes:6           ← 主从共 6 个节点

1.2 槽的计算:CRC16

text 复制代码
slot = CRC16(key) % 16384

16384 是固定值(不是节点数!)------槽是"逻辑位置",节点是"物理位置",两者解耦后,扩容/缩容只需要迁移槽,不需要重新哈希全部数据。


2. 请求路由:MOVED 与 ASK

2.1 MOVED:槽在别人那

客户端直连节点 A 请求一个属于节点 C 的 key,节点 A 返回 MOVED

text 复制代码
$ redis-cli -p 6380 GET user:42
MOVED 15880 127.0.0.1:6382

MOVED 15880 127.0.0.1:6382 = "slot 15880 在 6382,去那里"。智能客户端(redis-py 的 RedisCluster、redis-cli -c)会缓存槽-节点映射并自动重定向

text 复制代码
$ redis-cli -c -p 6380 SET user:42 "alice"
OK
$ redis-cli -c -p 6380 GET user:42
alice

2.2 ASK:槽正在迁移

槽迁移(扩容/缩容)期间,部分 key 已搬到目标节点。源节点对已搬走的 key 返回 ASK------与 MOVED 的区别:

MOVED ASK
含义 已永久属于对方 正在迁移,这个 key 暂时在对方
客户端处理 更新槽映射缓存 只重定向这一次,不更新缓存
text 复制代码
ASK 15880 127.0.0.1:6382

2.3 集群模式的功能限制

单节点可以跨 key 操作(MGET、事务、Lua),但槽不同就报 CROSSSLOT

text 复制代码
$ redis-cli -p 6380 MGET order:1001 user:42
(error) CROSSSLOT Keys in request don't hash to the same slot

集群模式下的限制汇总:

能力 限制
多 key 命令(MGET/MSET/SUNION...) 所有 key 必须同槽
MULTI 事务 / Lua 脚本 涉及的 key 必须同槽
SELECT 只有 db 0
管道/发布订阅 部分支持,跨槽受限
单 key 大对象 不受限,但会倾斜(Part 4 大 key 危害放大)

2.4 hash tag:把相关 key 钉进同一槽

官方 7.4 支持 hash tag :key 中 {...} 部分参与哈希,其余忽略。user:{42}:nameuser:{42}:cart 同槽,从而支持同槽 MGET/事务/Lua。

⚠️ 本机 8.10.0(cygwin 移植版)实测 hash tag 未生效CLUSTER KEYSLOT "user:{42}:name" = 6755、"user:{42}:cart" = 12984,不同槽!官方实现(cluster.ckeyHashSlot)应取 {} 内子串做 CRC16,本机移植版行为不符。该结论仅基于本机 8.10.0 移植版实测,标准发行版请在目标环境用 CLUSTER KEYSLOT 复核。

工程教训 :hash tag 是"跨 key 操作"的前提,上线前必须用 CLUSTER KEYSLOT 实测确认 tag 生效,不能默认所有发行版行为一致。若 tag 不可用,跨 key 业务要么改单实例,要么应用层聚合。


3. 主从与故障转移

集群的每个分片仍是一主一从(复制机制同 Part 10)。从库不参与分片,只做副本:

  • 主节点宕机 → 从库通过 gossip 检测(cluster-node-timeout,默认 15 秒)→ 从库自动提升为新主(无需哨兵!哨兵是集群外的独立组件,集群自带选举);
  • 数据与角色转移演示(本实验手动触发 CLUSTER FAILOVER):
text 复制代码
$ redis-cli -p 6383 CLUSTER FAILOVER     # 6383 是 6380 的从
OK
$ redis-cli -p 6383 cluster nodes
127.0.0.1:6383@16383 myself,master       ← 从库接管成为主
$ redis-cli -p 6383 cluster info
cluster_state:ok                          ← 集群仍健康
$ redis-cli -c -p 6383 GET order:1001
paid                                      ← 数据可继续访问

自动故障转移同样有"检测时间 + 选举"的不可用窗口(默认 15 秒级),且部分分片宕机时,只有该分片的槽不可用------这是集群相对哨兵(整个数据集)的故障半径优势。


4. 扩容缩容:槽迁移

扩容 = 加节点 → 从现有主节点迁出部分槽reshard):

text 复制代码
# 交互式迁移(或 --cluster-from/--cluster-to 指定源与目标)
redis-cli --cluster reshard 127.0.0.1:6380 \
  --cluster-from <源节点id> --cluster-to <新节点id> \
  --cluster-slots 1000 --cluster-yes

迁移期间访问中的 key 返回 ASK (§2.2),客户端需要处理。缩容同理反向迁移。槽迁移是数据拷贝,期间有内存/带宽开销------扩容要在低峰期做,且新节点先以"空槽主节点"加入。


5. 选型:哨兵 + 主从 vs 集群

维度 哨兵 + 主从 Redis Cluster
数据容量 单主上限 横向扩展(多分片)
写能力 单主上限 随分片增长
故障半径 整个数据集切换 仅宕机分片
复杂度 低(哨兵配置 + 客户端) 高(槽、重定向、跨槽限制)
跨 key 操作 无限制 受 CROSSSLOT 限制
适用 数据量 < 单机、写 QPS 可控 数据量/写 QPS 超单机

结论 :能单机就单机,需要高可用加哨兵;只有当单机内存或写吞吐成为瓶颈时再上集群------集群的跨槽限制会反过来约束业务(多 key 操作、事务、Lua)。


6. 版本与环境差异

差异点 官方 7.4 本机 8.10.0(cygwin 移植版)
槽分配/重定向 一致 一致(MOVED/ASK 实测正常)
hash tag keyHashSlot 支持 {} 实测未生效(§2.4)------上线前必须实测
故障转移 gossip + 从库提升 一致
集群命令 redis-cli --cluster 可用

7. 测试与验收

  • 集群测试(隔离环境):槽全覆盖(16384)、MOVED/ASK 重定向、CROSSSLOT 拒绝、CLUSTER FAILOVER 后数据可访问;
  • hash tag 验收:CLUSTER KEYSLOT 实测 {tag}:a{tag}:b 同槽(本机环境不满足!)。

本篇验收清单

  • 能解释"16384 槽 vs 节点数"的解耦设计(扩容只需迁槽);
  • 能区分 MOVED(永久归属)与 ASK(迁移中临时指向);
  • 能说出集群模式下跨 key 操作的限制(CROSSSLOT)与 hash tag 的作用;
  • 知道集群自带的从库提升机制与哨兵的差异;
  • 能在"哨兵 + 主从"与"集群"之间给出选型依据;
  • 搭建过三主三从集群并完成一次接管演练。

8. 常见误区

  1. "集群 = 多台机器各存各的" ------是分片不是节点分片,节点只是槽的宿主;扩容迁移的是槽。
  2. "集群可以替代哨兵"------集群自带故障转移,但跨 key 限制让很多业务无法直接迁移;小数据量上集群得不偿失(§5)。
  3. "hash tag 所有版本都支持" ------本机 8.10 移植版实测不生效;必须 CLUSTER KEYSLOT 验证(§2.4)。
  4. "MOVED 和 ASK 一样"------MOVED 永久更新路由缓存,ASK 只重定向单次(§2.2)。
  5. "集群里随便 MGET"------跨槽报 CROSSSLOT;需要同槽(hash tag)或应用层聚合。

9. 本篇小结

  • 分片:16384 槽解耦"逻辑位置"与"物理节点",扩容=迁槽;
  • 路由:MOVED(槽迁移后)/ ASK(槽迁移中)两种重定向;
  • 限制 :跨槽多 key 操作被 CROSSSLOT 拒绝,hash tag 是解药但必须实测
  • 选型:单机 → 哨兵 → 集群,逐级升级,集群的复杂度要用"确实超单机"来换取。

至此高可用三件套(复制、哨兵、集群)讲完。最后一篇 Part 12:性能、观测与生产排障 把整条知识链收拢到"问题怎么查":慢查询、延迟、大 key、热 key、连接治理与排障决策树。


10. 官方资料

相关推荐
zhanghaha13141 小时前
Python进阶教程:5_XML 解析 —— 新手完全指南
java·前端·数据库
祈禾10 小时前
Redis三大缓存问题与分布式锁
运维·数据库·redis·笔记·分布式·缓存
DBA小马哥11 小时前
关系型数据库核心概念手册:SQL、事务与存储引擎的技术脉络
数据库·sql
丫头,冲鸭!!!11 小时前
记账网站3-连数据库
数据库·个人开发
灯澜忆梦11 小时前
【MySQL12】进阶篇 | SQL优化
数据库·sql·mysql·性能优化
IvorySQL12 小时前
PostgreSQL 日报|PG18.5 回归测试崩溃问题(8 月 12 日)
大数据·数据库·人工智能·postgresql
ltl12 小时前
学习型查询优化器:Neo、Bao、Balsa 与 LLM-CBO
数据库
ltl12 小时前
持久内存退场之后:ZNS SSD 与下一代非易失内存
数据库
故乡dee云14 小时前
AWS 产品太多不会选?按“网站、数据库、文件、日志”4 类需求快速匹配
数据库·云计算·aws