Redis 10 · 集群:16384槽、扩缩容与请求路由

单机 Redis 的内存、连接和命令执行都集中在一台机器上。Cluster 把 Key 空间切成 16384 个槽位,让不同节点负责不同数据,同时通过 Gossip 传播拓扑和故障状态。

目录

  1. 槽位与请求归属
  2. [MOVED、ASK 与客户端路由](#MOVED、ASK 与客户端路由)
  3. [Hash Tag 与跨槽限制](#Hash Tag 与跨槽限制)
  4. [Gossip 与故障检测](#Gossip 与故障检测)
  5. 迁槽与扩缩容
  6. 集群设计边界

一、槽位与请求归属

Cluster 使用 CRC16(key) mod 16384 计算槽位。节点不按 Key 前缀直接分片,而是维护自己负责的槽位范围。

槽位是稳定的路由单位。扩容时迁移槽位,不需要把整个实例的数据集一次性搬走。

二、MOVED、ASK 与客户端路由

客户端连错节点时,节点返回 MOVED slot host:port,表示槽位归属已经稳定变化,客户端应更新拓扑缓存后重发。迁移过程中,目标节点可能返回 ASK,客户端只对下一次请求临时发送 ASKING,不能立即永久改写槽位表。

生产客户端必须支持集群模式、拓扑刷新、重试次数和跨节点 pipeline。普通单机客户端即使能连上某个节点,也无法正确处理 MOVED。

三、Hash Tag 与跨槽限制

Key 中的 {...} 是 Hash Tag:order:{1001}:itemsorder:{1001}:meta 只对花括号内容计算槽位,因此可以放在同一节点。

多 Key 命令、事务和 Lua 脚本通常要求所有 Key 在同一槽位。Hash Tag 能解决局部聚合,但不能把所有业务都塞进一个 Tag,否则热点会集中到单节点。

四、Gossip 与故障检测

节点通过 Cluster Bus 交换节点 ID、地址、槽位和故障标记。某节点先标记疑似故障,得到足够票数后形成失败共识,并触发副本晋升。

Cluster 的故障检测与 Sentinel 不同,客户端也不向 Sentinel 查询主节点;它从集群节点获得拓扑并自行路由。

五、迁槽与扩缩容

迁移一个槽位时,源节点和目标节点会经历导入、导出、逐 Key 搬迁和槽位确认。迁移期间请求可能收到 ASK,客户端必须按协议重试。

扩容应先加入空节点,再按负载均衡迁移槽位;缩容则先迁空目标节点负责的槽位,确认没有 Key 后再下线。迁移速度要受控,避免网络、CPU 和 fork 同时抖动。

六、集群设计边界

Cluster 解决水平分片和节点级故障,不自动解决跨槽事务、跨节点强一致和业务级热点。商品详情适合按商品 ID 分片,订单聚合要提前设计 Hash Tag 和读模型。

6.1 场景:商品详情上集群后,结算接口突然 CROSSSLOT

商品详情服务把库存、价格、限购计数分别设计为 product:stock:1001product:price:1001user:buy:42:1001。单机阶段,一段 Lua 可以原子校验库存并写限购;迁入 Cluster 后,脚本调用直接返回 CROSSSLOT Keys in request don't hash to the same slot

这里不能把异常当成客户端偶发错误重试,因为重试仍会落到不同槽位。若这些数据确实必须由一次脚本共同修改,Key 设计应以同一个业务聚合根 使用 Hash Tag,例如 product:{1001}:stockproduct:{1001}:price。但用户维度限购如果也塞进 {1001},热门商品会把所有用户请求打到同一槽,扩容形同虚设。

正确做法通常是分两层:库存扣减放在商品槽位并通过 Lua 保证原子;用户限购用独立分片或数据库唯一约束兜底;订单事件异步汇合。Hash Tag 是为了局部原子性,不是为了让所有相关数据"看起来在一起"。

6.2 场景:扩容时 ASK 激增,业务误判为 Redis 故障

给集群新增节点并迁移热点槽位时,监控里 ASK 响应短时间升高。一个自研客户端把所有重定向都按 MOVED 处理,收到 ASK 就刷新整个槽位表并永久改路由,导致一部分请求在源、目标之间来回跳,P99 延迟翻倍。

处理办法不是暂停迁槽,而是修正客户端协议:MOVED 更新本地槽位缓存;ASK 只对当前命令在目标节点前发送 ASKING,下一次仍按原槽位表路由,直到收到稳定 MOVED。迁槽操作同时应限速,并避开 AOF 重写、RDB 快照和大 Key 删除等重 I/O 时段。

扩容前还要检查槽位分布,而非只看节点内存。若热点 Key 的 Hash Tag 设计不当,新增节点也分不到热点;如果一个槽位本身极热,唯一有效的改造是拆 Key、分片计数或调整业务读模型。

6.3 用命令确认迁移是否真的完成

扩容窗口内不要只看云平台的节点列表。先用 CLUSTER INFO 确认 cluster_state:ok,再用 CLUSTER SLOTS 检查每个槽位的 owner;对正在迁移的节点执行 CLUSTER NODES,关注 migratingimporting 标记。迁移工具报告"完成"但仍有孤儿 Key 时,业务可能在重启后出现 CLUSTERDOWN Hash slot not served

迁移前应保存槽位分布和热点 Key 样本,迁移后比较各节点的 used_memory、命令吞吐和 P99。若某节点内存明显偏高,说明"槽位数量均匀"不等于"数据量均匀",需要继续拆分大 Key 或重新规划业务 Tag。


记住:槽位决定归属,MOVED 表示稳定路由变化,ASK 只表示迁移中的临时方向;扩容迁移的是槽位,不是简单复制整台机器。

相关推荐
泡海椒1 小时前
JQuick-java (JQuick-ASM)性能优化原理:字节码生成与缓存机制深度解析
java·缓存·性能优化
乐观的Terry1 小时前
Redis生产环境redis-conf配置教程
数据库·redis
SeaTunnel1 小时前
Redis 数据迁移不用写脚本:SeaTunnel 支持 String、Hash、Set、ZSet 四种数据类型
数据库·redis·哈希算法·数据迁移·seatunnel·数据同步
莫得感情 o1 小时前
Redis 11 · 缓存问题:穿透、击穿与雪崩
redis·缓存
kiss strong2 小时前
redis服务器登录(内网环境,无法使用客户端)
数据库·redis·缓存
来让爷抱一个16 小时前
2026 语义缓存实战:把命中契约写进SPEC,MonkeyCode 云端跑通
人工智能·机器学习·缓存
hweiyu0016 小时前
Redis命令:UNLINK
redis·缓存
Shaoxi Zhang16 小时前
Redis基础——五种核心数据结构(“容器”)
redis
志尊宝21 小时前
Vue3 零基础每日笔记(009):watch 侦听器——数据一变就“做事“
vue.js·笔记·缓存