分片应在单机出现硬瓶颈时启动,而非仅因数据量大;典型阈值包括内存活跃集超75%、连接数常超800、磁盘使用率超85%或写入超15k ops/sec且CPU超80%,同时需警惕锁竞争、路由开销等隐性瓶颈。

分片不是“数据多了就上”,而是“单机扛不住了才动”
分片的触发点从来不是文档总数,而是单台 mongod 实例在真实负载下暴露出的硬瓶颈:内存吃紧(RAM 持续 >90%)、磁盘 I/O 长期饱和、或连接数频繁打满(currentConnections 接近 maxIncomingConnections)。比如你有 5000 万条用户订单,但单机内存充足、查询延迟稳定、连接池余量大,那完全没必要分片——强行分片反而引入路由开销、事务限制和运维复杂度。
三个可量化的阈值参考(非绝对,但够用)
这些数字来自生产集群长期观测,适用于 MongoDB 4.4+、SSD 存储、中等复杂度查询(含二级索引):
-
内存:活跃数据集(working set)持续超过单机可用 RAM 的 75%,且
db.serverStatus().mem中resident接近virtual—— 此时 page fault 飙升,分片能分散热数据压力 -
连接数:
mongos或mongod的currentConnections经常 >800(默认上限),且业务侧出现Connection refused或超时重试——说明网络/连接池已成瓶颈,加mongos节点 + 分片是扩容正解 -
存储与写入:单 shard 磁盘使用率 >85%,或写入吞吐(
opcounters.write)持续 >15k ops/sec 且 CPU 利用率 >80% —— 单机磁盘带宽或 CPU 已到极限,无法靠优化索引解决
最容易被忽略的“隐性瓶颈”:查询路由与锁竞争
很多人等到磁盘爆了才分片,却没注意更早出现的信号:
- 在
mongos上执行db.currentOp({secs_running: {$gt: 5}}),发现大量操作卡在waitingForLock或waitingForFlowControl—— 这说明单 shard 的锁队列已在排队,分片能分流写锁争抢 -
mongos的 CPU 使用率异常高(>70%),而各 shard 负载不高 —— 很可能是查询路由层在做大量范围扫描或跨分片聚合,这时分片键设计比是否分片更关键 - 开启分片后,
sh.status()显示某些 chunk 迁移失败,日志里反复出现cannot move chunk: failed to clone chunk—— 说明原 shard 网络或磁盘已慢到无法支撑迁移,得先扩容单节点再分片
别踩“为分片而分片”的坑
以下情况上了分片反而倒退:
- 集合总数据量
- 业务强依赖跨分片事务(
session.startTransaction())或全局唯一索引 —— MongoDB 分片集群不支持跨 shard 的唯一约束(除非 shard key 是前缀),也仅支持有限事务语义 - 分片键选成
_id(默认 ObjectId)且不做哈希 —— 导致新写入全部打到一个 shard(monotonic 增长),热点问题比不分片还严重
真正该关心的,从来不是“多少数据该分片”,而是“当前瓶颈能不能被单机优化解决”。如果加内存、调 wiredTigerCacheSizeGB、建好覆盖索引、拆大文档都没用,那分片才是下一步。










