查看是否存在孤立文档
通过Mongo Shell连接MongoDB分片集群实例。
云数据库MongoDB的连接方法,请参见通过Mongo Shell连接MongoDB分片集群实例。
执行如下命令,切换至目标库。
use <db_name>执行如下命令,查看孤立文档信息。
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及以上版本
-
在可以连接分片集群实例的服务器上,创建一个用于清理孤立文档的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:待清理孤立文档的数据库名称数组。
-
-
在
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及以下版本
-
在可以连接分片集群实例的服务器上,创建一个用于清理孤立文档的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:需要替换为待清理孤立文档的集合名称,格式为数据库名称.集合名称。
-
-
在
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
-
在可以连接自建MongoDB数据库的服务器上下载cleanupOrphaned.js脚本文件。
wget "https://docs-aliyun.cn-hangzhou.oss.aliyun-inc.com/assets/attach/120562/cn_zh/1564451237979/cleanupOrphaned.js" -
修改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); }); -
执行如下命令,清理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.jsmongo --host 172.16.1.11 --port 27021 --authenticationDatabase admin -u dtstest -p 'Test123456' cleanupOrphaned.jsmongo --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" } }] )