技术干货 | MongoDB 偶遇孤儿文档及处理方法
孤儿文档的形成有 2 种原因:
① 正常的 shard 之间 chunk 均衡迁移,会产生孤儿文档,这个孤儿文档会在迁移结束后自动异步删除。
② shard 之间发生 chunk 均衡迁移的过程中,其中一些副本集发生 failover,可能会导致迁移失败,产生孤儿文档。
定位问题
使用环境:MongoDB 4.2.9 分片集群
研发反馈通过 id 查询 2 条数据,但实际返回了 3 条,并且这个 id 是唯一的,具体问题如下:
接下来,DBA 在 mongos 上查询如下结果(结果是2条):
这个结果明显和研发查询的结果不匹配,紧接着,将那 2 个 id 拿到所有分片上去查询,果然,同一个 id 出现在了 2 个 shard 上。因为这个集群之前几天由于业务不合理设计,频繁导致集群主从切换。开始怀疑孤儿文档。
db.collctionName.find().explain(true
查询结果如下:
现在确定了问题所在,接下来开始清理孤儿文档。
解决问题
下面的脚本可以遍历所有集合清理,不过在使用过程中,注意避开业务高峰期。(*其中的 test111 需要换成你对应的数据库名称)。
编辑一个 JS,文件名为 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 = 'test111'
db = db.getSiblingDB(dbName)
db.getCollectionNames().forEach(function(collName) {
cleanupOrphaned(dbName + "." + collName);
});
执行方法:
/opt/software/mongodb/mongodb-linux-x86_64-rhel70-4.2.18/bin/mongo --port xxxxx -uroot -pxxxxxx cleanupOrphaned.js
解释说明
读写偏好对孤儿文档的读取解释:
在分片集群下,balancer 在执行 moveChuck 的过程中,如果遇到 MongoDB 实例异常,就会导致孤儿文档的形成。这个孤儿文档在使用 readpreference 配置为 secondary pre 并且 readconcern 配置为 available 的时候会遇到读取到孤儿文档。MongoDB 默认从主库读会过滤掉这部分数据,但如果从读,默认不过滤。需要将 readconcern 配置为 local 避免读到孤儿文档。
官方解释:
文章转载自公众号: Mongoing中文社区