升级mongo3.2.1后遇到的数据重复的问题

因为5分钟的uv数据1分钟更新一次mongo,

所以使用了mongo的update方法(db.collection.update(query,update,true,false)),

设置第三个参数upsert为true,以实现数据不存在的时候直接写入,存在的时候更新的场景。

最近,在由mongo3.0.7升级到mongo3.2.1之后,发现,同样查询条件的数据,存在重复的情况。比如id=x是查询条件,根据update方法,找这条数据,往后面添加别的字段,如果那个字段已经存在,就往上面累加值,如果那个字段不存在,就加进去,如果找不到id=x的数据就直接插入,也就是id=x这个条件的数据,始终只有一条。可实际却出现了多条数据。

 

通过java代码起两个线程调用update的api,在表中不存在符合查询条件的数据的前提下,针对mongo3.2.1操作的时候,偶尔会发生符合更新条件的数据,写入两条的情况;针对mongo3.0.7在相同的测试次数下,未发生写入两条的情况。

 

public  void run(){
    try {
        MongoURI uri = new MongoURI("mongodb://IP地址:端口号/test");
        Mongo mongo = newMongo(uri);
        DB db = mongo.getDB(uri.getDatabase());
        DBCollection collection = db.getCollection("test1");

        BasicDBObject query = new BasicDBObject();
        query.put("ts", Long.valueOf("1455426000000"));
        query.put("lid", "102016021");
        query.put("type", "uv");

        String p1="pc";
        DBObject mappedUpdateObject =BasicDBObjectBuilder.start().push("$inc").add(p1,2).get();


        collection.update(query,mappedUpdateObject, true,false);

        mongo.close();
    } catch (Exception e) {
        // Die fast
       
throw new RuntimeException(e);
    }
}

 

 

publicstatic void main(String[]args){
    Test7 m=new Test7();//本类的名字
    Test5 n=new Test5();//功能相同的另外一个类,只不过,要写入的数据有差别,pc改成mobile,或者2改成3这样
    Thread t1 = new Thread(m);
    Thread t2= new Thread(n);
    t1.start();
    t2.start();

}

执行结果,在3.0.7的mongo上,不管起几个线程,结果始终只有一条。

而在3.2.1上,有时候是多条,有时候是一条。

根据网上搜索的资料,找到一个遇到类似情况的人,有人抛出一段mongo文档,

If all update() operations complete the query portionbefore any client successfully inserts data,and there is no uniqueindex on the name field, then each update operation may perform an insert.

 

指明了可能会发生此类问题,规避的措施是,在查询条件上建立唯一索引,

试着建了另外一张表,在lid,ts,type上建了唯一索引,

发现数据是不会重复多条了,但是是在偶发多条的时候,只有一条成功写入,另外一条不是更新上去,而是扔掉了。

 

以下为在网络上找到的资料:

在用C++MongoDB执行update操作的时候,如果设置了upsert参数为true,则会自动插入不存在的数据。在高并发环境下,会导致数据重复。

解决方法是为查询条件添加unique index,参考官方文档:

http://docs.mongodb.org/manual/core/write-operations-atomicity/

http://docs.mongodb.org/manual/core/index-unique/#index-type-unique

 

经过高压测试后,证明这个解决方案是靠谱的。

 


作者:达一夫
链接:http://www.zhihu.com/question/21703021/answer/20694219
来源:知乎

木有人回答,我自己来答吧。
首先mongodb的文档有解释:
If all update() operations complete the query portion before any clientsuccessfully inserts data,and there is no unique index on the namefield, then each update operation may perform an insert.

但这个解释不完全,在当前文档已经存在的情况下,多并发upsert,也可能插入多条,并且我们验证了这个可能性的存在。

嗯。。。我再添加一个问题吧。
find到的数据可能不是最新的,下一次find才是,这造成我们一些诡异的问题。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章