You need to enable JavaScript to run this app.
文档中心
数据库传输服务

数据库传输服务

复制全文
下载 pdf
常见通用问题
如何清理 MongoDB (分片集群架构)的孤儿文档
复制全文
下载 pdf
如何清理 MongoDB (分片集群架构)的孤儿文档
孤儿文档是指在数据库中存在,但因引用关系断裂、元数据丢失、分片不一致等情况,无法通过常规查询路径进行访问的文档,或是本应被删除却依旧残留的文档。本文介绍如何查询和删除孤儿文档。​
迁移影响​
DTS 在迁移集群时,会从 Shard 中抽取全量数据。正常文档和孤儿文档分布于不同的 Shard 上,DTS 不会对此进行区分,会将全部数据都迁移至目标库。DTS 对 MongoDB 迁移所采用的冲突策略为忽略,因此目标库最终的文档情况取决于哪个文档先被迁移过去,这可能导致数据内容或行数不一致。​
注意事项​
  • 文档数据库 MongoDB 版和自建 MongoDB 的孤儿文档清理方式一致。​
  • 查询孤儿文档命令会对所有 Shard 节点上的文档进行扫描,并遍历整个集合。当文档数据量较大时,查询耗时会较长,且会给数据库实例带来一定的查询压力,因此,建议在评估数据查询对业务的影响后,谨慎进行操作。​
  • 建议在业务低峰期直接清理孤儿文档。​
  • 清理操作需连接到集群的 Shard 节点。关于如何获取实例集群的 Shard 节点信息,请参见查看连接地址。​
  • 文档数据库 MongoDB 版的集群 Shard 节点默认未开放连接,若无法连接 Shard 节点,请开启 ShardIP 后再进行操作,或提交工单。​
  • 当实例中存在多个数据库时,需单独清理每个数据库中的孤儿文档。​
操作步骤​
说明​
下文以文档数据库 MongoDB 版实例为例,自建 MongoDB 实例的孤儿文档清理方式和文档数据库 MongoDB 版实例的清理方式一致。​
  1. 关闭源端 Balancer。​
  1. 通过 Mongo Shell 连接 MongoDB 实例。详细操作,请参见通过 Mongo shell 连接实例。​
  1. 执行以下命令关闭 Balancer。​
  • ​
    sh.stopBalancer()​
    ​
  1. 执行以下命令,验证是否关闭成功。​
  • ​
    sh.getBalancerState()​
    ​
  • 若返回为 false,则表示成功关闭 Balancer。​
  1. 暂停 MongoDB 实例的自动备份功能,避免备份系统自动重启 Balancer。​
  • 火山引擎的文档数据库 MongoDB 版实例当前不会自动重启 Balancer,因此无需暂停文档数据库 MongoDB 版实例的自动备份功能。请根据实际情况进行操作。​
  1. 查询孤儿文档​
  • 查询孤儿文档命令会对所有 Shard 节点上的文档进行扫描,并遍历整个集合。当文档数据量较大时,查询耗时会较长,且会给数据库实例带来一定的查询压力,因此,建议在评估数据查询对业务的影响后,谨慎进行操作。可直接进行孤儿文档的清理。​
  1. 通过 Mongo Shell 连接 MongoDB 实例。详细操作,请参见通过 Mongo shell 连接实例。​
  1. 执行以下命令,查看目标数据库集合上的孤儿文档,本文以 db_name.collection_01 (从 Secondary 节点读取)为例:​
  • ​
    db.getSiblingDB("db_name").collection_01​
    .find() ​
    .readPref("secondary") ​
    .readConcern("local") ​
    .explain("executionStats") ​
    ​
  • 参数说明:​
  • .find():表示查询 collection_01 集合所有文档。​
  • .readPref("secondary") :表示从 shard 从节点读(减轻主库压力)。​
  • .readConcern("local"):表示读取从节点最新本地数据(低延迟)。​
  • .explain("executionStats"):表示不返回数据,只返回执行性能统计。​
  1. 查看命令返回结果中 SHARDING_FILTER 阶段的 chunkSkips 属性,该属性值代表待检查集合在当前分片(Shard)节点上的孤儿文档数量。若该值大于零,则表明在该分片节点上存在孤儿文档。​
  • 命令输出示例如下所示:​
  • 表示在 SHARDING_FILTER 阶段之前的 COLLSCAN 阶段返回 103494661 个文档(nReturned: 103494661),在 SHARDING_FILTER 阶段过滤了 10 个文档(chunkSkips: 10),最终返回了 103494651 个文档(nReturned: 103494651),因此该示例中检测到 10 个孤儿文档。。​
  • ​
    {​
    queryPlanner: {​
    mongosPlannerVersion: 1,​
    winningPlan: {​
    stage: 'SHARD_MERGE',​
    shards: [​
    {​
    shardName: 'rs-mongo-shard-368c69*******-s4',​
    executionSuccess: true,​
    executionStages: {​
    stage: 'SHARDING_FILTER',​
    nReturned: 103494661,​
    executionTimeMillisEstimate: 48608,​
    works: 103494663,​
    advanced: 103494651,​
    needTime: 1,​
    needYield: 0,​
    saveState: 808552,​
    restoreState: 808552,​
    isEOF: 1,​
    invalidates: 0,​
    chunkSkips: 10,​
    inputStage: {​
    stage: 'COLLSCAN',​
    nReturned: 103494661,​
    executionTimeMillisEstimate: 18607,​
    works: 103494663,​
    advanced: 103494661,​
    needTime: 1,​
    needYield: 0,​
    saveState: 808552,​
    restoreState: 808552,​
    isEOF: 1,​
    invalidates: 0,​
    direction: 'forward',​
    docsExamined: 103494661​
    }​
    }​
    }​
    ]​
    }​
    },​
    serverInfo: {​
    host: 'mongo-shard-368c69*******-0',​
    port: 40000,​
    version: '4.0.3-57c7d591',​
    gitVersion: '57c7d591f4341da492e90c86476937d9215*******'​
    },​
    ok: 1,​
    operationTime: Timestamp({ t: 1767773112, i: 526 }),​
    '$clusterTime': {​
    clusterTime: Timestamp({ t: 1767773112, i: 532 }),​
    signature: {​
    hash: Binary(Buffer.from("55aba0423e8f1267a599152750b38496210*******", "hex"), 0),​
    keyId: Long("75535953704381*******")​
    }​
    }​
    }​
    ​
  1. 清理孤儿文档​
说明​
当实例中存在多个数据库时,需单独清理每个数据库中的孤儿文档。​
  1. 下载以下脚本文件至能直连 MongoDB Shard 节点的环境中,建议将脚本文件命名为 cleanupOrphaned.js,用于清理孤儿文档。​
  • ​
    function cleanupOrphaned(coll) {​
    var nextKey = { };​
    var result;​
    ​
    while ( nextKey != null ) {​
    result = db.adminCommand( { cleanupOrphaned: coll, startingFromKey: nextKey } );​
    ​
    if (result.ok != 1)​
    print("Unable to complete at this time: failure or timeout.")​
    ​
    printjson(result);​
    ​
    nextKey = result.stoppedAtKey;​
    }​
    }​
    ​
    var dbName = '<your_db_name>'​
    db = db.getSiblingDB(dbName)​
    db.getCollectionNames().forEach(function(collName) {​
    cleanupOrphaned(dbName + "." + collName);​
    });​
    ​
  1. 修改参数 var dbName 的取值为目标数据库的名称。​
  1. 执行以下命令,清理 Shard 节点下指定数据库中所有集合的孤儿文档。​
  • ​
    mongosh --host <ShardIP> --port <Primaryport> --authenticationDatabase <database> -u <username> -p <password> cleanupOrphaned.js​
    ​
  • 参数说明:​
  • ShardIP:Shard 节点的 IP 地址。​
  • Primaryport:Shard 节点中的 Primary 节点的服务端口。​
  • database:鉴权数据库名,即数据库账号所属的数据库。​
  • username:登录数据库的账号。​
  • password:登录数据库的密码。​
  • 示例如下,清理 shard0 节点的孤儿文档:​
  • ​
    mongosh --host 10.129.1.112 --port 3717 --authenticationDatabase admin -u root -p '*****' cleanupOrphaned.js > shard0.txt​
    ​
  1. 开启源端数据库实例的 Balancer,恢复源端数据库实例数据的自动均衡。​
说明​
待数据完成迁移后,可根据以下提示开启源端数据库实例的 Balancer。​
  1. 通过 Mongo Shell 连接 MongoDB 实例。详细操作,请参见通过 Mongo shell 连接实例。​
  1. 执行以下命令关闭 Balancer。​
  • ​
    sh.startBalancer()​
    ​
  1. 执行以下命令,验证是否开启成功。​
  • ​
    sh.getBalancerState()​
    ​
  • 若返回为 true,则表示成功开启 Balancer。​
  1. 按需开启源端数据库实例的自动备份功能。​
当一直无法完成孤儿文档的清理时怎么办?​
若孤儿文档对应的命名空间(namespace)上存在空闲游标(idleCursors),则可能致使清理过程始终无法完成,并且在对应孤儿文档的 MongoDB 守护进程(mongod)日志中会出现如下信息:​
​
Deletion of DATABASE.COLLECTION range [{ KEY: VALUE1 }, { KEY: VALUE2 }) will be scheduled after all possibly dependent queries finish​
​
您可通过 Mongo Shell 连接至 mongod 并执行以下命令,以查看当前分片上是否存在空闲游标。若存在,则需通过 restart mongod 或者 killCursors 命令清理所有空闲游标后,重新清理孤儿文档。更多信息,请参见 Jira 工单。​
​
db.getSiblingDB("admin").aggregate( [{ $currentOp : { allUsers: true, idleCursors: true } },{ $match : { type: "idleCursor" } }] )​
​
最近更新时间:2026.08.12 17:59:04
这个页面对您有帮助吗?
有用
有用
无用
无用