removeShard卡在completed但sh.status()仍显示该分片,说明config server残留记录,需清理db.shards、db.databases中primary引用及db.migrations中committed迁移记录,并清空原节点dbPath元数据。

removeShard卡在completed但sh.status()仍显示该分片
这说明命令看似成功,但config server里还有残留记录。最常见原因是db.shards集合没被清理干净,或者该分片仍被某个数据库设为primary。
实操建议:
- 先连到config副本集主节点(不是mongos),执行
use config,再查db.shards.findOne({ _id: "shard_id" })—— 若返回非空,直接db.shards.deleteOne({ _id: "shard_id" }) - 运行
sh.status()确认该分片是否还在输出里;如果还在,说明shards集合或database集合中仍有引用 - 检查所有数据库的primary归属:
db.databases.find({ "primary": "shard_id" }),若有结果,必须先用movePrimary迁走,再删shards记录
执行过removeShard但目标节点重启后又自动加入集群
这是因为原分片节点的dbPath里还存着shardIdentity文档和旧的集群元数据,mongod启动时会读取并尝试注册,导致冲突或拒绝加入。
实操建议:
- 停掉该节点的
mongod进程 - 清空整个
dbPath目录(或至少删掉_mdb_catalog_version、所有collection-*.wt、index-*.wt、shardIdentity.bson等文件) - 不要只删
shardIdentity就重启——其他元数据残留仍可能触发校验失败 - 重启前务必确认
sh.status()和db.runCommand({ listShards: 1 })都不再包含该_id
config.migrations里残留“committed”但目标分片已不存在
这类记录不会自动清理,会导致后续moveChunk或均衡器反复报ConflictingOperationInProgress,本质是元数据认为迁移已完成,但实际数据从未落地。
实操建议:
- 连接config主节点,查
db.migrations.find({ state: "committed", to: "shard_id" }),确认to字段指向已下线分片 - 再查对应
min/max范围在源分片上是否真实存在数据:db.collection.find({ shard_key: { $gte: ..., $lt: ... } }).limit(1) - 若源分片有数据、目标分片已不可达,才安全删除该migration记录:
db.migrations.deleteOne({ ... }) - 别漏掉
db.chunks里对应chunk的shard字段——它可能还指向已删除分片,需人工修正或等cleanupOrphaned介入
cleanupOrphaned执行后仍有空块,但sh.status()显示chunk数不为零
cleanupOrphaned只清理“元数据说属于我、但我本地没数据”的文档,它不修改config.chunks,所以chunk计数不会变。真正要归零,得靠均衡器把剩余chunk搬走,或手动moveChunk。
实操建议:
- 先确认该分片是否已从
sh.status()消失;如果还在,说明它还没真正退出集群,cleanupOrphaned不该在它身上运行 -
cleanupOrphaned必须在目标分片的PRIMARY节点上执行,且命令里的库名集合名要完全匹配,不能带通配符 - 如果
sh.status()里某分片remaining.chunks > 0但db.collection.countDocuments()为0,大概率是chunk路由表错乱,此时应优先检查config.chunks中该分片的记录是否全被误删
整个过程里最容易被忽略的是:**removeShard返回"completed"只是操作流程结束,不代表元数据已同步清理干净;真正的终点是sh.status()不显示、config.shards无记录、原节点dbPath彻底清空——三者缺一不可。**











