必须人工干预清理残留锁与迁移记录:先停均衡器,再删config.migrations中aborted/aborting文档和config.locks中balancer/movechunk锁,接着flushrouterconfig刷新路由缓存,最后重启均衡器。

MongoDB 4.4 中分片事务异常残留的锁资源(如 moveChunk 锁或 balancer 锁)不会自动清理,必须人工干预;否则后续均衡、迁移、甚至某些集合操作都会被阻塞。
怎么确认 config.locks 里有残留的 moveChunk 或 balancer 锁
直接连到 config server 副本集的 primary 节点(不是 mongos),执行:
db.getSiblingDB("config").locks.find({ _id: { $in: ["balancer", /moveChunk/] } }).pretty()
如果返回结果中存在 state: "locked" 或 state: "taking" 且 who 字段指向一个早已不存在的进程(比如 PID 已消失、host 不可达),基本就是残留锁。特别注意:4.4 不支持 locks 集合的自动过期,when 时间戳远早于当前时间也说明是死锁。
为什么不能只删 locks,还要停均衡器并清理 migrations
在 4.4 分片集群中,locks 和 migrations 是强关联的:一个 moveChunk 操作会同时写入 config.migrations(记录状态)和 config.locks(占位防并发)。如果只删 locks,下次均衡器启动时会扫描 migrations,发现有 state: "aborting" 或无状态但 when 很老的文档,就会拒绝继续工作,并重新加锁。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 必须先运行
sh.stopBalancer()(通过 mongos)——否则删锁瞬间可能触发新迁移 - 再连 config server primary,删
migrations中所有异常项:db.getSiblingDB("config").migrations.deleteMany({ state: { $in: ["aborted", "aborting"] } }) - 再删对应锁:
db.getSiblingDB("config").locks.deleteMany({ _id: { $in: ["balancer", /moveChunk/] } })
删完锁之后要不要 flushRouterConfig 或重启 mongos
要。4.4 的路由缓存(chunk metadata)不会因 config 数据库变更而自动刷新。如果跳过这步,mongos 可能仍按旧的、错误的 chunk 分布转发请求,导致写入失败或读到陈旧数据。
- 在任意 mongos 上执行:
db.adminCommand({ flushRouterConfig: 1 }) - 然后才执行
sh.startBalancer() - 不建议重启 mongos 进程——它会导致客户端连接闪断,且 4.4 的
flushRouterConfig已足够可靠
目标分片上出现孤儿 chunk 怎么办
如果迁移中断前已把部分数据复制到目标分片,但元数据没提交(即 config.chunks 里该 chunk 的 shard 字段仍是源分片),那些“多出来”的数据就是孤儿 chunk。4.4 不提供自动清理命令,必须人工判断:
- 查
config.chunks确认该 chunk 当前归属:db.getSiblingDB("config").chunks.findOne({ min: { shardKey: ... }, max: { shardKey: ... } }) - 若
shard是源分片,但目标分片上db.collection.countDocuments()明显偏高,就需登录目标分片,用db.collection.remove()清理范围外的数据(务必带精确的min/max查询条件) - 切勿直接
drop整个集合——可能混有正常 chunk
这个步骤容易被跳过,但一旦忽略,后续迁移或查询可能持续报错或返回重复/缺失数据。










