故障现象
业务上并无对这个表的delete操作,通过mongostat可以查看。但是mongos对一个表进行count操作时,发现它的计数结果会慢慢变少,然后突然有一个大幅增长,随后又逐渐减少,现象如下
mongos> db.ebay_us_detail.count()
154462481
mongos> db.ebay_us_detail.count()
154462463
mongos> db.ebay_us_detail.find().count()
154686915
mongos> db.ebay_us_detail.find().count()
154686850
mongos> db.ebay_us_detail.find().count()
154686769
mongos> db.ebay_us_detail.find().count()
154873243
mongos> db.ebay_us_detail.find().count()
154873088
故障原因
我查了下oplog,发现某个分片上存在这么一个操作,标记为d,即delete操作
udb-dm5jbg:PRIMARY> db.oplog.rs.findOne({"ns":"ebay.ebay_us_detail","op":"d"})
{
"ts" : Timestamp(1514210377, 16),
"t" : NumberLong(2),
"h" : NumberLong("-6024794084103163788"),
"v" : 2,
"op" : "d",
"ns" : "ebay.ebay_us_detail",
"fromMigrate" : true,
"o" : {
"_id" : ObjectId("5a3a5f1d71c2475fee1f26b6")
}
}
通过这条记录大概猜测后台正在move chunk,通过mongod日志确认后台确实正在针对该表进行move chunk,猜测这是一个bug
1 通常情况下,一个分片上的数据属于该分片上的chunk
2 然而在move chunk过程中,如果move chunk没有完成,数据虽然还在这个分片上,但是这个chunk已经不属于这个分片了
3 这时在这个分片上执行count时,只会统计在这个分片上并且属于这个分片的chunk的记录数,不会统计在这个分片上但不属于这个分片的chunk上的记录数,所以count操作会不准,出现上述的故障现象,慢慢减少,突然又增加
4 如果是非count操作,普通的query肯定无法容忍这种错误的,所以非count操作会额外去查看在这个分片上,需要的chunk确实属于该分片;如果该chunk不属于该分片,则操作会被阻塞,直到move chunk完成。所以move chunk时的性能会急剧下降,但是确保数据正确
5 count为啥不去额外统计不属于这个分片的chunk呢,这既是一个bug,也是一种折中的考虑。可以认为一般业务并不需要非常精准的count结果,但是count速度比较重要,不去额外统计的话,就可以使用覆盖索引,而检查某个记录是否属于一个有效的chunk这种操作是个比较费时的操作,无法使用索引
改进措施
1 修改源码,count统计方法和普通query一样,即正确性第一,效率第二
2 设置负载均衡窗口期,在窗口期内业务不要指望准确的count操作
参考
https://jira.mongodb.org/browse/SERVER-8405