哨兵的盲区:内存天花板
主从加哨兵,可用性齐了,但所有从库都是主库的完整镜像——数据总量被钉死在单机内存上限上。业务数据涨到几十上百 GB,单机装不下、fork 越来越慢、大实例的持久化与迁移处处是坑(持久化篇的预告在这里兑现)。出路只有分片:把数据切开,每个节点只装一小块。Redis Cluster 就是官方的分片方案,分片加副本二合一,不再需要哨兵。
16384 个槽:数据的门牌号
Cluster 的分片规则不在节点数上做除法,而是引入一个中间层:16384 个哈希槽(slot)。每个 key 按公式定位:
slot = CRC16(key) mod 16384
item:detail:10086 --> slot 8281 --> 节点A
user:session:9527 --> slot 12182 --> 节点B每个节点负责一段槽区间,key 按槽就位。为什么是「槽」而不是直接按节点哈希?因为槽是数据与节点之间的解耦层:扩容缩容时移动的是槽,key 跟着槽走,映射关系的调整粒度可控——这是预分片思想,和第 9 篇的多副本打散一脉相承。有个细节:想要多个 key 落进同一个槽(同槽才能做多 key 操作),用 hash tag——key 里花括号圈住的部分参与哈希:order:{1001}:info 与 order:{1001}:items 永远同槽。
重定向与 smart client
key 发到了不归它管的节点怎么办?节点不代劳,回一个 MOVED 错误,附上正确的节点地址——「这 key 不归我,去问 A」。每次都重定向浪费一个来回,所以 Cluster 的客户端都是 smart client:本地维护「槽到节点」的映射表,绝大多数请求直接命中正确节点,MOVED 收到一次就刷新一次映射。槽迁移过程中的过渡态则用 ASK 错误处理:本次去新节点试试,但映射表不变——它是「一次性指路」,MOVED 是「搬家通知」。
节点之间互相发现、交换状态,靠的是 gossip 协议:每个节点随机找几个节点互发消息,集群状态像八卦一样传遍全网——没有中心节点,故障判定最终由多数派拍板,与哨兵的仲裁思路一脉相承。
代价清单:多 key 操作的枷锁
分片不是免费午餐,代价列在明面上:跨槽的多 key 命令直接报错——MGET 打散在三个节点上的 key、跨槽的 Lua、跨槽事务都不可用,只能用 hash tag 凑槽或客户端自己拆分聚合;扩容迁移最怕大 Key——槽迁移以 key 为粒度,一个几百 MB 的大 key 迁移时阻塞两边节点(大 Key 篇又添一条罪状);运维复杂度上升——节点规划、槽分配、故障演练都要跟上。所以选型收束成一句话:数据量单机装不下、或写 QPS 单机扛不住,上 Cluster;只是要高可用,主从加哨兵更简单。能用简单架构解决的,别急着上复杂架构。
到这里,Redis 自身的机制——内存、过期、复制、持久化、哨兵、分片——全部盘完。视野重新拉回应用层:本地缓存与分布式缓存怎么搭成多级体系?命中率这个核心指标怎么算、怎么养?下半场从第 16 篇开始。
评论 (0)