removeShard后sh.status()仍显示已下线分片,因该命令不清理config server元数据:db.shards中残留_id、db.databases中primary指向该分片、db.migrations中有committed状态且to字段为其ID。

直接连 config 主节点删 db.shards、db.databases 和 db.migrations 里的残留记录,再清空原分片节点的 dbPath,否则 sh.status() 会一直显示已下线的分片。
为什么 removeShard 后 sh.status() 还显示该分片
因为 removeShard 命令只触发数据迁移和 draining,不清理 config server 中的元数据引用。常见残留点有三个:db.shards 里还存着 _id 记录;某个数据库仍把该分片设为 primary;db.migrations 里有 state: "committed" 但 to 字段指向已下线分片。
执行 db.shards.findOne({ _id: "shard_id" }) 若返回结果,说明第一层残留未清;执行 db.databases.find({ primary: "shard_id" }) 若有输出,必须先用 movePrimary 迁走,不能跳过;db.migrations.find({ state: "committed", to: "shard_id" }) 的记录若存在且目标不可达,就需手动删除——否则均衡器后续会反复报 ConflictingOperationInProgress。
cleanupOrphaned 执行后 chunk 数没变,是不是没生效
不是没生效,是它本来就不改 config.chunks。该命令只扫描 shard 本地数据,删掉“元数据说不属于我、但我磁盘上真有”的文档,属于数据层清理,不影响 config server 的 chunk 分布记录。
sh.status() 显示的 chunk 总数来自 config.chunks,而 cleanupOrphaned 不碰这个集合。所以即使孤儿文档已被清空,chunk 计数仍维持原样。真正要修正 chunk 元数据,得靠 moveChunk 或等待 cleanupOrphaned 触发的后台 chunk 校验逻辑(前提是配置了 orphanCleanupDelaySecs)。
注意:cleanupOrphaned 必须直连 shard 的 primary 节点 执行,连 mongos 或 config server 会静默失败或返回 "ok" : 0;连 secondary 会执行但不写入,stoppedAtKey 始终为 null。
原分片节点重启后又自动注册进集群
这是 dbPath 里残留了 shardIdentity.bson 和其他 WiredTiger 元数据文件,mongod 启动时读到就会尝试向 config server 自注册,导致冲突或被拒绝加入。
不要只删 shardIdentity.bson —— 至少还要清掉:_mdb_catalog_version、所有 collection-*.wt、index-*.wt。更稳妥的做法是停掉进程后整个清空 dbPath 目录(前提是你确认数据已全部迁出且无其他用途)。
清完务必验证两件事:sh.status() 输出里不再出现该分片名;db.runCommand({ listShards: 1 }) 返回结果中 shards 数组也不含它。缺一不可。
最易被忽略的是 db.chunks 里仍有 shard 字段指向已删除分片——这不会被 removeShard 或 cleanupOrphaned 自动修正,得人工 update 或等 cleanupOrphaned 后续触发的 orphan cleanup 流程介入,但后者不保证及时性。











