技术干货 | MongoDB 偶遇孤儿文档及处理方法

guwj
发布于 2022-12-2 10:56
浏览
0收藏

孤儿文档的形成有 2 种原因:

① 正常的 shard 之间 chunk 均衡迁移,会产生孤儿文档,这个孤儿文档会在迁移结束后自动异步删除。

② shard 之间发生 chunk 均衡迁移的过程中,其中一些副本集发生 failover,可能会导致迁移失败,产生孤儿文档。

定位问题

使用环境:MongoDB 4.2.9 分片集群

研发反馈通过 id 查询 2 条数据,但实际返回了 3 条,并且这个 id 是唯一的,具体问题如下:


技术干货 | MongoDB 偶遇孤儿文档及处理方法-鸿蒙开发者社区


接下来,DBA 在 mongos 上查询如下结果(结果是2条):


技术干货 | MongoDB 偶遇孤儿文档及处理方法-鸿蒙开发者社区


这个结果明显和研发查询的结果不匹配,紧接着,将那 2 个 id 拿到所有分片上去查询,果然,同一个 id 出现在了 2 个 shard 上。因为这个集群之前几天由于业务不合理设计,频繁导致集群主从切换。开始怀疑孤儿文档。


db.collctionName.find().explain(true查询结果如下:


技术干货 | MongoDB 偶遇孤儿文档及处理方法-鸿蒙开发者社区


现在确定了问题所在,接下来开始清理孤儿文档。

解决问题

下面的脚本可以遍历所有集合清理,不过在使用过程中,注意避开业务高峰期。(*其中的 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 避免读到孤儿文档。

官方解释:


技术干货 | MongoDB 偶遇孤儿文档及处理方法-鸿蒙开发者社区




文章转载自公众号: Mongoing中文社区


分类
标签
已于2022-12-2 10:56:43修改
收藏
回复
举报
回复
    相关推荐