Redis 分片集群:它到底是怎么把数据分片又路由的?

主从复制和哨兵能解决高并发读和高可用,但有两个天花板它俩都够不着。

一个是海量数据存储,一个是高并发写。

面试的时候,Redis 分片集群是必问的一题,这篇文章就把这条线彻底讲透。

一、为什么主从不够用

单台 Redis 不是不能扛,是扛不到太高。

主从模式下永远只有一个 master 在写,数据再多也逃不出这一台机器的内存上限。

写请求再猛,写并发也被这一个 master 卡死。

海量数据往哪塞?高并发写谁来解决?

这时候就该分片集群上场了。

二、先说结论:分片集群到底解决什么

一句话:

分片集群就是给 Redis 做「横向扩容」,让多个 master 一起扛。

它同时顶住三件事。

存储上,数据被切成多份摊到不同 master,容量跟着节点数线性涨。

写上,每个 master 都能接受写请求,写并发上限被直接打破。

读上,每个 master 还能自己挂多个 slave,读写都顶得住。

还有一件事常被忽略:

高可用也不靠哨兵了,master 之间互相盯,自己就把哨兵的活干了。

客户端访问任意节点都行,集群自动把请求路由到正确的节点。

三、多 master:把数据拆开存

分片集群里不再是「一个 master 领着 slave」的主从关系,而是多个 master 各自存不同的数据。

打个比方。

原来只有一个仓管,所有货架归他管。

现在招了多个仓管,每人分管不同的货架。

假设一个仓管能管 20G,三个合起来就是 60G,容量随仓管数量走。

每个 master 自己还能挂多个 slave,所以它同时具备主从的特征:

多 slave 解决高并发读,多 master 解决高并发写。

四、哈希槽:数据到底落在哪个节点

这是分片集群的核心机制。

它引入了一个概念叫哈希槽(hash slot),一共 16384 个。

创建集群时,把这 16384 个槽平均分给各个主节点。

比如三个主节点,各自认领一段:

  • 节点一:0 ~ 5460
  • 节点二:5461 ~ 10922
  • 节点三:10923 ~ 16383

当你写一条数据,比如 set user:9527 小飞龙

第一步,对 key 的有效部分算 CRC16 哈希值。这里 user:9527 的哈希值是 16071。

第二步,拿它模 16384:16071 % 16384 = 16071。

第三步,16071 落在节点三的槽区间(10923 ~ 16383),这条数据就存到节点三。

读数据同理,算哈希、模 16384、找到对应节点。

我把 key 到槽位的映射逻辑贴一段(Redis 源码思路):

java 复制代码
// Redis 中 key 到槽位的映射
public int slotOf(String key) {
    String effective = extractBracePart(key); // 取 {...} 内有效部分;无括号则取整个 key
    return CRC16(effective.getBytes()) % 16384;
}

private String extractBracePart(String key) {
    int start = key.indexOf('{');
    int end = key.indexOf('}');
    if (start >= 0 && end > start + 1) {
        return key.substring(start + 1, end); // 大括号内作为有效部分
    }
    return key; // 没有大括号,整个 key 就是有效部分
}

五、key 的有效部分:把相关业务放一起

有时候你希望同一业务的多个 key 落到同一个节点,方便批量操作。

Redis 允许用大括号指定「有效部分」。

比如 set {shop}1001 手机,计算哈希时只看 {shop} 里的内容。

shop 的哈希值是 3808,模 16384 得 3808,落在节点一(0 ~ 5460),数据就存到节点一。

再写 {shop}1002{shop}1003,只要大括号里都是 shop,它们全落在节点一。

没有大括号时,整个 key 就是有效部分。

这个设计很巧妙:

相同业务设相同有效部分,就能聚在同一个节点,跨 key 的批量读写不用在节点间来回跳。

六、master 互 ping:哨兵的活它自己干了

主从高可用要靠哨兵(Sentinel)盯着。

分片集群里不需要哨兵了。

master 之间互相发 ping 做心跳检测。

如果多个 master 都认为某个 master 主观下线,就把它标记为客观下线,然后触发主从切换。

这跟哨兵功能一模一样,只是去中心化了。

七、客户端访问任意节点都行

机器这么多,客户端该连谁?

答案是连谁都行。

集群节点之间做了自动路由。

你发请求到任意节点,它算完 key 的槽位,发现不该自己管,就把请求转发到正确的节点。

所以你既不需要哨兵,又自动具备了哨兵的全部能力。

八、主从 vs 分片集群,一张表看清

维度 主从集群 分片集群
数据存储 全量复制,受单 master 容量限制 多 master 分片,容量随节点线性扩展
写能力 仅单 master 可写 多 master 均可写
读能力 多 slave 分担 每 master 可挂多 slave
高可用 依赖哨兵 master 互 ping,去中心化
客户端路由 直连指定节点 访问任意节点,自动路由

数据来自 Redis 官方 Cluster 规范:

固定 16384 个哈希槽,用 CRC16 算法分配。

九、面试怎么答

面试碰上 Redis 分片集群,答三层就够了。

第一层,它解决什么问题?

单节点 Redis 有容量和写并发两个天花板。分片集群用多个 master 分片,存储容量随节点线性涨,写并发被多个 master 摊开;每个 master 还能挂 slave 扛读,master 互 ping 替代哨兵做高可用。

第二层,数据怎么存、怎么取?

核心是 16384 个哈希槽。

写数据时,对 key 的有效部分算 CRC16,模 16384 得到槽位,槽位归哪个节点就存哪。

有效部分默认是整条 key;如果 key 带大括号 {xxx},就用括号里的内容算,这样同业务的 key 能聚到同一节点。

读数据同样算槽位、找节点。

第三层,客户端连谁?

连任意节点都行,集群内部自动路由。

相关推荐
吃饱了得干活1 小时前
Java Map 核心原理:从数据结构到 put/get 执行,一篇彻底讲透
java·后端
不才不才不不才1 小时前
Spring 源码系列(17): HandlerMapping 与 HandlerAdapter 两大体系
java·后端·spring
Seven971 小时前
AI杂谈:别再问AI会不会替代你,先看你是不是驾驶员
人工智能·后端
ERD Online2 小时前
我们怎么设计 good first issue:让第一个 PR 两小时内合入
数据库·git·后端·开源·issue
IT_陈寒2 小时前
Vite热更新失效?我的几个犯傻操作害我debug两小时
前端·人工智能·后端
凤山老林2 小时前
Spring Boot 大文件处理实战:分片上传、断点续传与 OSS 集成
java·spring boot·后端·大文件上传·分片上传·断点续传
卷无止境2 小时前
Python 依赖管理这件事,到底该看哪个文件
后端·python
卷无止境3 小时前
FastAPI 缓存方案全解析:从内存到分布式的工程实践
后端·python
程序员爱钓鱼3 小时前
Rust 可变借用详解:&mut T 与安全修改数据
后端·面试·rust