那这和本次的数据不一致又有什么关系呢?抖精神的地方来了,mongodb 对于均衡分片的处理方式是:先将 shard 1 节点的 chunk 拷贝到 shard 2 节点去,当 chunk 完全拷贝完成后,在将 shard 1 节点的 chunk 删了。
那么在这个转移的过程中,大家就可以想到,有好几个环节都会发生意外,从而导致块迁移失败。
排查到这里,就有必要和用户确认当天的操作流程了。
果不其然,当天其实发生过服务器断网,而这个断网就是在业务刚刚接入的10分钟后。让我们来还原案发现场。
用户开启同步任务,数据开始按预期向目标端数据库按规则同步。
同步10分钟后,机房断网,此时数据同步任务处于重试阶段,mongodb 集群全部断开网络。
断开网络期间,mongodb 在进行的块迁移被迫终止。
一段时间后,网络恢复,数据同步自动重试机制保证用户无需人工干预,继续开始同步任务。
mongodb 继续开始块迁移。
发现没有,在第五步的时候,mongodb 的块迁移并没有去干预之前块迁移失败的结果,其实这么说不严谨,mongodb config server 上记录的元数据还是认为这个块在 shard1 上,而已经从 shard 1 节点 copy 到 shard 2 节点的数据并没有被删除。因此最终 count 出来的数据就会有大于原来数据总数的情况。
解决那为了解决这个问题,其实官方是有预见的。给出了官方的解决方案。
这里我帮大家总结好了,执行下面这段脚本在各个分片节点上。
var nextKey = { }; vard result; while ( nextKey != null ) { result = db.adminCommand( { cleanupOrphaned: "<COLLECTION>", startingFromKey: nextKey } ); if (result.ok != 1) print("Unable to complete at this time: failure or timeout.") printjson(result); nextKey = result.stoppedAtKey; }这段脚本就在做一件事情:找出不属于 config 节点记录的数据标识范围,并将其删除。
总结那通过这件事情,查看官方文档,我们总结了几点:
在使用数据同步工具迁移数据到 mongodb 分片集群的时候,需要作如下动作
停止平衡器:如何停止平衡器
使用cleanOrphan命令:如何清理孤儿文档
面对数据不一致性,排查思路可以从数据库、同步逻辑出发
专业的事交给专业的人做。