chunk迁移卡住实为流程阻塞于catching_up/cloning/committing等中间态,需查config.migrations中超30分钟未更新的记录确认;安全终止须直连源分片primary执行db.killop(),再清理migration记录及孤儿数据。

Chunk迁移失败不是“锁死”状态,而是迁移流程卡在某个中间态(如 catching_up、cloning 或 committing),导致后续 balance、split 甚至部分查询被阻塞。修复关键在于定位卡点、安全终止迁移、清理元数据不一致,而非重启服务或强行删库。
怎么确认迁移真卡住了而不是慢?
仅看 sh.status() 或 sh.isBalancerRunning() 不够——它们不反映实时迁移进度。必须查 config.migrations 集合:
- 连任意 mongos,执行:
db.getSiblingDB("config").migrations.find({ "state": { $in: ["catching_up", "cloning", "committing"] } }).toArray() - 若返回非空,且某条记录的
lastModified超过 30 分钟没更新,基本就是卡住 - 特别注意
state: "catching_up":这阶段依赖源分片 oplog 同步进度,若 secondary 落后太多,它就一直等,不会超时自动退出
如何安全终止卡住的 moveChunk?
不能在 mongos 上执行 db.killOp(),也不能 kill 进程。必须直连正在执行迁移的源分片 primary:
- 先查操作 ID:
db.currentOp({ "secs_running": { $gt: 60 }, "command.moveChunk": { $exists: true } }) - 拿到
opid后,用 mongo shell 直连该源分片的 primary(不是 mongos),再执行:db.killOp(<opid>)</opid> - 杀掉后,源分片上 chunk 数据仍存在,但 config 中 migration 记录会标记为
failed;此时 chunk 可能变成jumbo或orphaned,需后续清理
清理残留元数据和孤儿 chunk
删 migration 记录只是第一步,真正要解决的是 config 和实际分片数据之间的不一致:
- 连 config 副本集 primary(不是 mongos),执行:
db.migrations.deleteMany({"state": {$in: ["catching_up","cloning","committing"] } }) - 对已标记
"state": "committed"但目标分片不可达的记录,先用db.chunks.findOne()确认该 chunk 在源分片上是否还完整存在,再删对应 migration - 最后运行:
db.runCommand({cleanupOrphaned: "db.collection"})(替换为实际库名和集合名)——这个命令只清理“元数据说 chunk 在某 shard,但该 shard 上查不到”的情况,不会误删有效数据
最容易被忽略的点是:cleanupOrphaned 命令必须在目标分片确实缺失数据时才起作用;如果目标分片只是临时宕机后恢复,它本地可能残留 _tmp_moveChunk_* 临时目录,需手动清理,否则下次迁移可能因文件冲突失败。











