图解 MongoDB 27|分片策略:范围分片 vs 哈希分片

上一篇讲了片键设计的三个目标,这一篇讲片键选好后,怎么分------范围分片还是哈希分片。这是同一个片键的两种分散策略,它们直接决定了:范围查询能不能定向、写入会不会热点。选错了,要么查询全广播,要么写入堆在一个 shard。

先把机制边界说清楚

MongoDB 把数据按片键划分成 chunk,划分方式有两种:

  • 范围分片(Ranged Sharding) :按片键值的大小范围划分。比如片键是数值,[1,1000) 一个 chunk、[1000,2000) 一个 chunk。相邻的值在同一个 chunk(大概率同一 shard)。
  • 哈希分片(Hashed Sharding):按片键值的哈希划分。先算片键值的哈希,按哈希值范围划分。相邻的原始值,哈希后分散到不同 chunk。

两者的本质差别是:范围分片保留了片键的顺序性,哈希分片打散了顺序性。这个差别决定了它们各自擅长什么。

范围分片 vs 哈希分片

范围分片的优势是范围查询能定向 。因为相邻的片键值在同一个 chunk/同 shard,查询 {createdAt: {$gte: X, $lt: Y}} 这种范围条件,mongos 能算出涉及哪些 chunk,定向到对应 shard,不用广播。这对时间范围、数值区间的查询非常友好。

范围分片的劣势是单调递增会热点。如果片键单调递增(时间戳、自增 ID),所有新数据的片键值都比现有的大,全落进「最大值」那个 chunk,而这个 chunk 通常在最后一个 shard。于是所有写入集中到一个 shard,形成严重热点------这个 shard 扛着全部写入,其他 shard 闲置,完全失去了分片的负载分散意义。

哈希分片的优势是写均匀分散。哈希把单调递增的值打散成随机分布,写入均匀打到各个 shard,没有热点。这对写入量大的场景(日志、事件流、IoT)非常关键。

哈希分片的劣势是范围查询无法定向。哈希后片键值失去了顺序性,原本相邻的值分散到不同 chunk。范围查询不知道涉及哪些 chunk,只能广播到所有 shard。所以哈希分片不适合有范围查询需求的场景。

怎么选

选择的核心是两个问题:业务有没有范围查询?片键会不会单调递增?

有范围查询需求(时间、数值区间)→ 范围分片。但要确保片键不是单调递增的,否则热点。如果片键本身就是递增的(比如时间),范围分片会热点,这时要么换片键,要么用下面的混合策略。

无范围查询、按 ID 等值查询 → 哈希分片。写入均匀是最大优势,ID 等值查询能定向(按哈希值定位 chunk)。日志、事件、按文档 ID 查的场景适合。

两者都要(既有范围查询又怕热点)→ 混合策略。几种做法:

  • 复合片键 {范围字段, 哈希字段} :比如 {userId, 时间} 范围分片,userId 分散写入、时间聚合同用户数据。或者对单调键加一个分散前缀。
  • 对单调递增键做哈希分片 + 辅助索引:片键用哈希保证写均匀,范围查询靠在非片键字段建索引(虽然查询会广播,但索引在各 shard 内高效)。
  • 权衡接受广播:如果范围查询不频繁,哈希分片 + 偶尔广播也能接受。

几个实际场景的推荐

日志/事件流(写入大、按 ID 查、偶尔按时间扫):哈希分片(按文档 ID 或机器 ID 哈希),写均匀是第一优先。

用户内容/订单(按用户维度访问) :范围分片 {userId, 时间},用户查询定向、单用户数据聚集、写入按用户分散。

时间序列数据(按时间范围查、写入单调递增) :最棘手的场景。纯时间范围分片会热点。可用 {标签字段, 时间} 复合片键(标签字段分散写入,时间保范围查询),或桶模式 + 哈希。

纯 ID 查询(KV 场景):哈希分片,简单高效。

判断框架

  • 范围分片保范围查询、牺牲写分散;哈希分片保写均匀、牺牲范围查询。
  • 高频范围查询 → 范围分片,但警惕单调递增热点。
  • 写入大、ID 等值查询 → 哈希分片。
  • 两者都要 → 复合片键或哈希+辅助索引。
  • 时间序列是最难的场景,用复合片键或桶模式。
  • 记住:范围查询多别用哈希;写入怕热点别用范围分单调键。

排查落点:范围与哈希分片

这一节的边界可以压成一句话:范围分片保留局部性,哈希分片打散写入。

线上出问题时,哈希片键改善分布但牺牲范围查询定向能力。 分片和治理问题不能只看节点数量,要看片键、chunk、路由命中、热点和恢复演练。

排障时不要漏掉的三件事

排障追问一:这个设计等到数据增长后会先暴露什么问题?

范围分片保留局部性,哈希分片打散写入。

排障追问二:什么情况下这个结论会失效?

哈希片键改善分布但牺牲范围查询定向能力。

排障追问三:用哪些证据确认它真的成立?

对比目标查询是否带片键、是否范围扫描、写入是否单调递增。

下一篇讲 chunk 和 balancer,看清数据怎么在 shard 间均衡。


关于十三Tech

我是十三,长期关注服务端架构、数据库、中间件和 AI 工程实践。

我相信好的技术文章应该能回到真实系统里,帮人少踩一次坑。


关于十三Tech

All in AI Agent 方向的架构师,专注 AI 工程实践。

相信 AI 是程序员的最佳搭档,帮助每一位开发者驾驭 AI。

公众号搜索「十三Tech」

本文首发:rubyfun.cn/posts/%E5%9...

相关推荐
再吃一根胡萝卜19 分钟前
微服务治理的“四大护法”:从 Django 视角理解 Spring Cloud 核心组件
后端
再吃一根胡萝卜21 分钟前
面试终极挑战:如何用 Django 经验,回答 Java 微服务实战问题?
后端
怕浪猫1 小时前
DeepSeek Harness 源码实战第3章:Profile / Bundle / Patch——dsh 的装配系统
openai·agent·ai编程
To_OC1 小时前
装完 ESLint 它一声不吭?我还以为代码写得多好
后端·node.js·eslint
凤山老林2 小时前
精细化流量治理:Spring Boot 动态特性开关与灰度发布体系
java·spring boot·后端
vipbic3 小时前
一个前端的 9 天重构:我是怎么用 Codex 重做航栈的
前端·javascript·后端
冬奇Lab4 小时前
Code Agent 解剖(04):系统提示词是怎么组装的,agent 的「人格」从哪来?
人工智能·开源·agent
一点一木5 小时前
Hermes Desktop 重磅更新,Bot Mode 正式上线——把你的 AI 变成一支可协作的专属团队
人工智能·agent
考虑考虑6 小时前
Excel导入时产生特殊字符处理
java·后端·java ee
IT_陈寒6 小时前
Redis的DEL命令竟然没删掉数据?我踩的这个坑你得知道
前端·人工智能·后端