reshardCollection卡住通常非自身逻辑慢,而是被长事务、锁争抢或I/O瓶颈阻塞;需查currentOp定位waitingForFlowControl/waitingForLock操作,检查磁盘IOPS、CPU负载及应用是否漏传分片键。

reshardCollection 被卡住,先看 currentOp 里有没有长事务
reshardCollection 本身不支持中断重试,一旦启动就只能等它完成或失败。但实际卡住往往不是 reshard 逻辑本身慢,而是被其他长事务或未释放的锁拖住——尤其是那些开了 session 但没 commit/abort 的事务。
执行以下命令查活跃操作:
db.currentOp({ "secs_running": { "$gt": 30 }, "active": true })
重点关注字段:secs_running > 30、command.reshardCollection 为 null(说明不是 reshard 自身)、type 为 op 或 txn、ns 涉及目标集合。这类操作极可能持有写锁,阻塞 reshard 的 chunk 迁移步骤。
- 若发现
secs_running> 300 的updateOne或findAndModify,且client来自业务服务 IP,需立即联系对应团队终止该会话 - 若
type是txn且state为inProgress,说明事务未结束;用killOp终止前务必确认该事务无副作用(如已写入中间状态) - 不要依赖
maxTimeMS:它对已持有的锁无效,只影响新请求排队超时
resharding 进度停在某个百分比,检查 waitingForFlowControl
reshardCollection 进度条长时间卡在 37%、62% 等固定值,currentOp 中大量操作状态为 waitingForFlowControl 或 waitingForLock,基本可断定是 I/O 或锁资源争抢导致。
这不是配置问题,而是物理瓶颈:
- 所有参与迁移的分片节点,其磁盘必须能同时扛住三路压力:旧 chunk 读取 + 新 chunk 写入 + journal 刷盘。机械盘几乎必然卡死
- SSD 随机写 IOPS 必须 ≥ 3000;NVMe 建议 ≥ 10000。用
iostat -x 1观察%util是否持续 > 95% - 如果 config server 或 mongos 所在机器 CPU 负载 > 80%,也会拖慢元数据协调,导致迁移线程空转等待
commitReshardCollection 能不能用来“强行收尾”?
不能把它当成“跳过等待”的快捷键。调用 commitReshardCollection 的真实效果是:提前触发写锁,把剩余迁移强制串行化执行,而非并行推进。
它只在一种场景下有用:当前预估剩余时间 > 2 秒,但你确认业务可以接受一次更长的写入暂停(比如 ≤ 15 秒),且希望尽快结束整个过程。
- 执行前必须确保没有长事务、I/O 无瓶颈、所有节点负载正常;否则只会把卡顿从“分散”变成“集中爆发”
- 命令格式严格为
db.adminCommand({ commitReshardCollection: "db.collection" }),少引号或大小写错误会直接报no such cmd - 执行后无法回退,且不会缩短总耗时——只是把延迟集中到一个时间点
最容易被忽略的阻塞点:应用层还在发单键查询
reshardCollection 启动后,MongoDB 会立刻启用双键校验机制。此时若应用仍按旧习惯发 find({ name: "zhangsan" }),服务器不会执行,而是直接返回错误:Cannot target a shard key that is not present in the query。
这个错误看似无关,实则会干扰均衡器和迁移协调器的内部状态判断,尤其在高并发下可能引发 config server 元数据更新延迟,间接拖慢 reshard 进度。
- 必须全量改造应用代码,在所有 CRUD 操作中显式带上新旧分片键字段,哪怕用
{$exists: true}占位 - 聚合管道中
$match阶段同样受约束,漏掉任一键都会被拒绝 - 监控日志里搜
shard key that is not present,比看 reshard 进度更早暴露问题











