MongoDB分片集群中balancer默认不合并chunk,仅负责迁移;7.0+版本自动合并仅适用于非分片集合,分片集合需手动执行defragmentCollection且须停用balancer、满足分片状态等前提。

Chunk数量过多时,MongoDB不会自动合并
默认情况下,MongoDB的balancer只负责迁移chunk,不执行合并(merge)操作。哪怕你有几百个1MB的chunk堆在一个shard上,只要总大小远低于chunkSize(默认64MB),balancer也完全无视——它没有“主动收缩”逻辑。这是最容易被误解的一点:很多人以为均衡器会“清理碎片”,其实它只管“搬大块”,不管“捏小块”。
7.0+版本靠自动数据段合并,但仅限非分片集合或特定场景
MongoDB 7.0起确实在单分片(即非分片集合)或某些内部元数据结构中启用了自动数据段合并,但对分片集群中的普通集合无效。分片集合的chunk仍是独立管理单元,合并必须显式触发。如果你在sh.status()里看到某shard上chunk数暴涨(比如5000+)、storageSize远大于size,且avgObjSize异常低,那基本确认是小chunk堆积导致的磁盘空洞,不是自动机制能解决的。
手动合并需用defragmentCollection,但有硬性前提
从MongoDB 6.0开始,可通过configureCollectionBalancing命令启用defragmentCollection选项来合并小chunk,但必须满足以下全部条件:
- 目标集合必须已分片,且
chunkSize未被人为调小(否则合并后立刻又被分裂) - 执行前需停用balancer:
sh.setBalancerState(false) - 该操作只能在
mongos上发起,且要求所有相关shard处于PRIMARY状态(不能在recovering、migrating中) - 合并过程会清空chunk的放置历史,可能导致快照读取失败或事务报
StaleChunkHistory错误
示例命令(在mongos中执行):
db.runCommand({
configureCollectionBalancing: "db.collection",
defragmentCollection: true
})
真正有效的长期解法是预防而非事后合并
合并只是补救,代价高、风险大、不持久。更关键的是堵住源头:
- 绝不要把
chunkSize设低于默认64MB——哪怕看到“均衡慢”,调小只会让问题恶化 - 分片键必须避开低基数字段(如
status、type)和单调递增字段(如timestamp),否则新写入永远挤在尾部chunk,旧chunk变冷后空洞无法复用 - 上线前用真实流量压测,确保
sh.status()中各shard的chunk数量偏差≤±15%
一旦chunk数量失控,修复成本远高于设计阶段选对分片键和保持默认chunkSize。


















