Cluster 集群
单机内存有上限,Cluster 把数据分片到多节点,同时自带高可用(每个分片有副本)。面试主线:槽位怎么分、客户端怎么找到数据、扩容怎么迁。
槽位模型
16384 个槽分配到节点
- 整个集群固定 16384 个槽,key 的归属由
CRC16(key) % 16384决定 - 每个节点负责一段槽区间,槽是数据迁移的最小单位
- 节点之间通过 gossip 协议交换状态(PING/PONG),不用中心协调节点
客户端寻址:MOVED 与 ASK
客户端发命令时,节点判断 key 的槽是否归自己:
- MOVED 重定向:槽不在本节点。返回
MOVED <slot> <ip:port>,客户端更新本地槽映射缓存,下次直连目标节点。槽映射是稳定的,所以只发生一次 - ASK 重定向:槽正在迁移中。返回
ASK,客户端先发ASKING再发命令,不更新缓存(槽还在迁)
区别一句话:MOVED 是“槽不归我管,以后也别找我”;ASK 是“槽在迁,这次帮我带过去”。
数据迁移(扩缩容)
扩容加节点、缩容减节点都靠在线迁移槽(redis-cli --cluster reshard):
- 目标节点准备接收槽
- 源节点把槽内的 key 逐个迁移(MIGRATE 命令,原子)
- 迁移期间访问该槽:命中的 key 直接服务,没迁到的返回 ASK
- 迁完广播槽归属变更
过程不中断服务,但迁移有开销:大 key 迁移慢、网络带宽占用、迁移中的 key 访问变慢。
Cluster 的限制
| 限制 | 说明 |
|---|---|
| 多 key 操作 | 必须同槽才支持(事务、Lua、mget) |
| hash tag | {user:123}:cart 花括号内参与 CRC16,强制同槽 |
| 跨槽事务 | 不支持 |
| 单 key 大小 | 大 key 无法分散,仍是单点压力 |
| 数据分布 | 槽均匀但数据不保证均匀(取决于 key 分布) |
哨兵 vs Cluster
| 维度 | 哨兵 | Cluster |
|---|---|---|
| 分片 | 无(单分片) | 有(16384 槽) |
| 容量扩展 | 不能(换大机器) | 在线扩节点 |
| 高可用 | 自动故障转移 | 分片副本自动转移 |
| 复杂度 | 低 | 高(槽、重定向、迁移) |
选型:数据量单机能装下用哨兵;容量要横向扩展用 Cluster。
面试追问
- 16384 槽怎么来的? CRC16 的结果对 16384 取模。槽数固定,节点增减只改槽归属
- MOVED 和 ASK 的区别? MOVED 槽归属已变,客户端更新缓存直连;ASK 槽在迁移,一次性的,不更新缓存
- Cluster 的键能跨节点操作吗? 不能,多 key 操作要求同槽。用 hash tag 强制相关 key 落同一槽
- 扩容时数据怎么迁? reshard 在线迁移槽,MIGRATE 逐 key 迁移,期间 ASK 重定向。不中断服务但占带宽
- 哨兵和 Cluster 怎么选? 容量够用要简单高可用用哨兵;要横向扩展容量用 Cluster