全部产品
Search
文档中心

数据传输服务 DTS:如何清理MongoDB(分片集群架构)的孤立文档

更新时间:Sep 23, 2026

查看是否存在孤立文档

  1. 通过Mongo Shell连接MongoDB分片集群实例。

    云数据库MongoDB的连接方法,请参见通过Mongo Shell连接MongoDB分片集群实例。

  2. 执行如下命令,切换至目标库。

    use <db_name>
  3. 执行如下命令,查看孤立文档信息。

    db.<coll_name>.find().explain("executionStats")
    说明

    查看每个分片executionStats中SHARDING_FILTER 阶段(stage)的chunkSkips字段,如果不为0,则表示对应的分片上存在孤立文档。

    如下返回示例表示:在SHARDING_FILTER 阶段之前的FETCH阶段返回了102个文档("nReturned" : 102),然后在SHARDING_FILTER 阶段过滤了2个孤立文档("chunkSkips" : 2),最终返回了100个文档("nReturned" : 100)。

    "stage" : "SHARDING_FILTER",
    "nReturned" : 100,
    ......
    "chunkSkips" : 2,
    "inputStage" : {
        "stage" : "FETCH",
        "nReturned" : 102,

    关于SHARDING_FILTER阶段的更多信息,请参见MongoDB Manual。

清理孤立文档

重要

如果您有多个数据库,需清理每个数据库的孤立文档。

云数据库 MongoDB 版

说明

MongoDB 4.2以下大版本或4.0.6以下小版本的实例在执行清理脚本时会报错。如何查看实例当前版本,请参见MongoDB小版本说明。如何升级小版本和大版本,请参见升级数据库大版本和升级数据库小版本。

清理孤立文档需要使用cleanupOrphaned命令。在MongoDB 4.4及以上版本和MongoDB 4.2及以下版本中的使用方法略有区别,具体操作方式如下。

MongoDB 4.4及以上版本

  1. 在可以连接分片集群实例的服务器上,创建一个用于清理孤立文档的JS脚本,脚本名称为cleanupOrphaned.js。

    说明

    该脚本用于清理多个Shard节点的多个数据库中所有集合的孤立文档。如需清理特定集合中的孤立文档,可自行修改JS脚本来完成。

    // shard实例名称列表
    var shardNames = ["shardName1", "shardName2"];
    // 数据库列表
    var databasesToProcess = ["database1", "database2", "database3"];
    shardNames.forEach(function(shardName) {
        // 遍历指定的数据库列表
        databasesToProcess.forEach(function(dbName) {
            var dbInstance = db.getSiblingDB(dbName);
            // 获取该数据库实例的所有集合名称
            var collectionNames = dbInstance.getCollectionNames();
            // 遍历每个集合
            collectionNames.forEach(function(collectionName) {
                // 完整的集合名称
                var fullCollectionName = dbName + "." + collectionName;
                // 构建 cleanupOrphaned 命令
                var command = {
                    runCommandOnShard: shardName,
                    command: { cleanupOrphaned: fullCollectionName }
                };
                // 执行命令
                var result = db.adminCommand(command); 
                if (result.ok) {
                    print("Cleaned up orphaned documents for collection " + fullCollectionName + " on shard " + shardName);
                    printjson(result);
                } else {
                    print("Failed to clean up orphaned documents for collection " + fullCollectionName + " on shard " + shardName);
                }
            });
        });
    });

    您需要对脚本中的shardNames和databasesToProcess参数的值进行修改,具体说明如下:

    • shardNames:分片集群实例中待清理孤立文档的Shard节点的ID数组,您可以在实例基本信息页面的Shard列表区域获取,例如d-bp15a3796d3a****。

    • databasesToProcess:待清理孤立文档的数据库名称数组。

  2. 在cleanupOrphaned.js脚本所在的目录下,执行以下命令清理孤立文档。

    mongo --host <Mongoshost> --port <Primaryport>  --authenticationDatabase <database> -u <username> -p <password> cleanupOrphaned.js > output.txt

    参数说明如下。

    参数

    说明

    <Mongoshost>

    分片集群实例Mongos节点的连接地址,格式为s-bp14423a2a51****.mongodb.rds.aliyuncs.com。

    <Primaryport>

    分片集群实例Mongos节点的端口号,默认为3717。

    <database>

    鉴权数据库名,即数据库账号所属的数据库。

    <username>

    数据库账号。

    <password>

    数据库账号的密码。

    output.txt

    执行结果保存到output文件中。

MongoDB 4.2及以下版本

  1. 在可以连接分片集群实例的服务器上,创建一个用于清理孤立文档的JS脚本,脚本名称为cleanupOrphaned.js。

    说明

    该脚本用于清理多个Shard节点中指定数据库下指定集合的孤立文档。如需清理数据库中多个集合的孤立文档,您可以修改fullCollectionName参数并多次执行,也可以自行修改脚本通过遍历的方式执行。

    function cleanupOrphanedOnShard(shardName, fullCollectionName) {
        var nextKey = { };
        var result;
        while ( nextKey != null ) {
            var command = {
                runCommandOnShard: shardName,
                command: { cleanupOrphaned: fullCollectionName, startingFromKey: nextKey }
            };
            result = db.adminCommand(command);
            printjson(result);
            if (result.ok != 1 || !(result.results.hasOwnProperty(shardName)) || result.results[shardName].ok != 1 ) {
                print("Unable to complete at this time: failure or timeout.")
                break
            }
            nextKey = result.results[shardName].stoppedAtKey;
        }
        print("cleanupOrphaned done for coll: " + fullCollectionName + " on shard: " + shardName)
    }
    var shardNames = ["shardName1", "shardName2", "shardName3"]
    var fullCollectionName = "database.collection"
    shardNames.forEach(function(shardName) {
        cleanupOrphanedOnShard(shardName, fullCollectionName);
    });

    您需要对脚本中的shardNames和fullCollectionName参数的值进行修改,具体说明如下:

    • shardNames:分片集群实例中待清理孤立文档的Shard节点的ID数组,您可以在实例基本信息页面的Shard列表区域获取,例如d-bp15a3796d3a****。

    • fullCollectionName:需要替换为待清理孤立文档的集合名称,格式为数据库名称.集合名称。

  2. 在cleanupOrphaned.js脚本所在的目录下,执行以下命令清理孤立文档。

    mongo --host <Mongoshost> --port <Primaryport>  --authenticationDatabase <database> -u <username> -p <password> cleanupOrphaned.js > output.txt

    参数说明如下。

    参数

    说明

    <Mongoshost>

    分片集群实例Mongos节点的连接地址,格式为s-bp14423a2a51****.mongodb.rds.aliyuncs.com。

    <Primaryport>

    分片集群实例Mongos节点的端口号,默认为3717。

    <database>

    鉴权数据库名,即数据库账号所属的数据库。

    <username>

    数据库账号。

    <password>

    数据库账号的密码。

    output.txt

    执行结果保存到output文件中。

自建MongoDB

  1. 在可以连接自建MongoDB数据库的服务器上下载cleanupOrphaned.js脚本文件。

    wget "https://docs-aliyun.cn-hangzhou.oss.aliyun-inc.com/assets/attach/120562/cn_zh/1564451237979/cleanupOrphaned.js"
  2. 修改cleanupOrphaned.js脚本文件,将test替换为待清理孤立文档的数据库名。

    重要

    如果您有多个数据库,您需要重复执行步骤2~步骤3。

    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 = "test"
    db = db.getSiblingDB(dbName)
    db.getCollectionNames().forEach(function(collName) {
            cleanupOrphaned(dbName + "." + collName);
    });
  3. 执行如下命令,清理Shard节点中指定数据库下所有集合的孤立文档。

    说明

    您需要重复执行本步骤,为每个Shard节点清理孤立文档。

    mongo --host <Shardhost> --port <Primaryport>  --authenticationDatabase <database> -u <username> -p <password> cleanupOrphaned.js
    说明
    • <Shardhost>:Shard节点的IP地址。

    • <Primaryport>:Shard节点中的Primary节点的服务端口。

    • <database>:鉴权数据库名,即数据库账号所属的数据库。

    • <username>:登录数据库的账号。

    • <password>:登录数据库的密码。

    示例:

    本案例的自建MongoDB数据库有三个Shard节点,所以需要分别为这三个节点清除孤立文档。

    mongo --host 172.16.1.10 --port 27018  --authenticationDatabase admin -u dtstest -p 'Test123456' cleanupOrphaned.js
    mongo --host 172.16.1.11 --port 27021 --authenticationDatabase admin -u dtstest -p 'Test123456' cleanupOrphaned.js
    mongo --host 172.16.1.12 --port 27024  --authenticationDatabase admin -u dtstest -p 'Test123456' cleanupOrphaned.js

异常处理

若孤立文档对应的namespace上存在idleCursors,则可能会导致清理过程一直无法完成,且在对应孤立文档的mongod日志中存在如下信息:

Deletion of DATABASE.COLLECTION range [{ KEY: VALUE1 }, { KEY: VALUE2 }) will be scheduled after all possibly dependent queries finish

您可以通过Mongo Shell连接mongod并执行如下命令,可以查看当前分片上是否存在idleCursors。如果存在,则需要通过restart mongod或者killCursors命令清理所有idleCursors后,重新清理孤立文档。更多信息,请参见JIRA ticket。

db.getSiblingDB("admin").aggregate( [{ $currentOp : { allUsers: true, idleCursors: true } },{ $match : { type: "idleCursor" } }] )