ChunkTooBig错误是MongoDB对超限chunk迁移的硬性拦截,主因是写入倾斜与长期未分裂致chunk远超64MB;需手动sh.splitAt()分裂,而非调大chunkSize。
为什么
错误总在迁移时爆发
这不是集群“坏了”,而是 MongoDB 在强制拒绝一个超过上限的 chunk 迁移——它已经大到无法被目标分片接收。根本原因通常是写入倾斜 + 长期未分裂,导致某些 chunk 膨胀到远超默认 64MB。注意:
不是警告,是硬性拦截,后续所有涉及该 chunk 的迁移、平衡、甚至某些聚合操作都可能卡住。
典型诱因:按时间戳字段分片(如
),新数据全写入最新 chunk;或用低基数字段(如
)做片键,导致大量文档挤在同一个 chunk
关键点:
报错本身不显示具体 chunk 大小,得靠
或
手动查
别急着调大
!盲目设成 256MB 只会让问题延后更难收拾
怎么安全地触发大 chunk 分裂(
命令实操)
MongoDB 不会自动分裂超大 chunk,必须手动干预。核心是用
或
指定分割点,但前提是片键值存在且分布合理。
先定位问题 chunk:
找出
下 size 最大的 chunk,记下它的
和
片键值
验证分割点是否存在真实文档:
: {
:
,
:
}}).limit(1),确保中间有数据可切
执行分裂:
:
}),
必须严格落在当前 chunk 的
范围内,且最好是该范围内高频出现的值
失败常见原因:
超出范围、对应文档不存在、集合正在迁移中(
进行中)、或分片副本集状态异常
设多少才不算瞎猜
默认 64MB 是通用值,不是金科玉律。设太小(如 16MB)会导致 chunk 数暴增,元数据压力大、balancer 频繁调度;设太大(如 256MB)则单个 chunk 容易再次触达
上限,且迁移耗时长、影响可用性。
参考公式:
,例如每天增 9GB、6 个分片 → 约 500MB/天/分片 → chunkSize 设 128MB 较稳妥
写入模式决定下限:如果业务有明显冷热分离(如日志类),chunkSize 可适当放大;如果是用户行为类均匀写入,64MB 仍是最稳选择
修改后不会立即重分:已存在的 chunk 保持原大小,只影响新 chunk 的生成;老 chunk 需手动
或等自然写入分裂(极慢)
配置命令:
,需在
执行,对所有分片生效
平衡器(
)开着,为啥 chunk 就是不自动拆
balancer 只负责迁移 chunk,从不过问 chunk 内部是否过大。它看到的是“这个 chunk 太大”,但没有权限和逻辑去执行
—— 这是管理员要干的事。所以即使 balancer 正常运行,
依然会卡死迁移流程。
检查 balancer 状态:
和
,但它们和分裂无关
真正要盯的是
输出里的
分布,以及每个 chunk 的
字段(单位字节)
自动分裂只发生在插入时:当新文档写入导致 chunk 接近上限,且片键值刚好落在边界附近,才会触发;但已达 256MB 的 chunk,插入也不再触发分裂
最易忽略的一点:如果集合启用了
的
,连 balancer 都会被禁用,此时 chunk 困在原地,连迁移都停了
chunk 分裂不是开关一开就完事的操作,它依赖片键设计合理性、数据分布真实性、以及人工对分割点的判断。一旦 chunk 超过 200MB,自动机制基本失效,手动
是唯一出路。
ChunkTooBigChunkTooBigcreated_atstatus: "active"ChunkTooBigsh.status()db.collection.getShardDistribution()chunkSizesplitsh.splitAt()sh.splitFind()sh.status()database.collectionminmaxdb.collection.find({shardKey$gtminValue$ltmaxValuesh.splitAt("database.collection", {shardKeysplitValuesplitValuemin/maxsplitValuemoveChunkchunkSizeChunkTooBigchunkSize ≈ 单日新增数据量 / (分片数 × 3)splitdb.runCommand({ setParameter: 1, chunkSize: 128 })mongosbalancersplitChunkTooBigsh.getBalancerState()sh.isBalancerRunning()sh.status()chunkssizecollModnoBalance: truesplitAt