MongoDB遇到疑似数据丢失的问题不要用InsertMany!

最近做数据备份的时候发现了有个很严重的问题,那就是数据丢失(最后证明没丢,是别的问题造成的)。

问题如下:

我通过两种方式在两个mongoDB集群中,对一组collection进行备份,最后2个备份数据的数据个数不相同,并且都小于原始collection的count结果。于是便开始寻求解决办法,流程如下:

1、记录3组数据,原始数据集按条件count有909217个数据,备份代码如下,其中replaceOne备份下来的数据有907582条,而使用insertMany备份下来的结果有906281条(注释是之后加的,之前用的是insertMany):

    rdd.foreachPartition { x => {       
        val mongoURI = new MongoClientURI(uri)
            val mongo = new MongoClient(mongoURI)
            val db = mongo.getDatabase("wenshu")
            val dbColl = db.getCollection("testbackup")
                       
            val mongoURI2 = new MongoClientURI(uri2)
            val mongo2 = new MongoClient(mongoURI2)
            val db2 = mongo2.getDatabase("wenshu")
            val dbColl2 = db2.getCollection(backName)
           
            var count = 0
            var resList = new ArrayList[Document]
            x.foreach(y => {
//              count = count + 1
//              resList add y
                try{
                    dbColl.replaceOne(eqq("_id", y.get("_id")), y, new UpdateOptions().upsert(true))
                    dbColl2.insertOne(y)
                }catch{
                    case e: Throwable => e.printStackTrace()
                }
               
//              使用这种方式插入会导致插入的数据和真实数据数量对应不上, 先注释掉有机会再找原因
//              if (count == 10000){
//                  try{                   
//                      dbColl2.insertMany(resList, new InsertManyOptions().ordered(false))
//                  }catch{
//                      case e: Throwable => e.printStackTrace()
//                  }
//                  resList.clear
//                  count = 0
//              }
            })
//          if (count > 0)
//              try{                   
//                  dbColl2.insertMany(resList, new InsertManyOptions().ordered(false))
//              }catch{
//                  case e: Throwable => e.printStackTrace()
//              }

2、通过查询stackoverflow和jira发现数据丢失问题曾经存在过,但都是2.0之前的mongodb,现在商用化之后的mongodb基本没人出现过数据丢失问题。

3、检查代码,发现不是插入代码错误。

4、对抽出来的907582条数据的库进行备份,还是用上述程序,发现replaceOne的数据有907582,而insertmany只有904291条数据。

5、结合上述条件,推测是insertMany导致部分数据丢失,所以才会出现insertMany结果和replaceOne不一样。

6、对此结论进行测试,将insertMany改为上述代码中的insertOne重新备份907582条数据。

7、结果正确,重新备份下来的2份数据都是907582条。目前解决了其中一个问题,就是备份出来的两份数据不一样多的问题,接下来考虑备份数据和从总库中抽取的数据不一致的问题。

8、对mongo shell的count操作查找其工作原理,发现有一些报告count数据不准的问题,结合自身原因推测是count的问题,数据应该只有907582条。

9、通过多抽取几遍对这个问题进行测试,按同样条件抽了3遍返回的结果都是907582条,可以认定数据库中只有907582条满足此条件的数据。

结论:

1、MongoDB的Count操作有可能返回错误的结果。至少在Sharding Cluster,多个索引和2级索引的条件下会出现这种问题。

2、插入时不要使用InsertMany,会导致数据丢失。

3、同理,尽量不要使用updateMany,虽然不会导致数据丢失,但是按照结论2推测有可能出现某些数据更新失败的情况。

更多MongoDB相关教程见以下内容

MongoDB 的详细介绍:请点这里
MongoDB 的下载地址:请点这里

相关推荐