一个mongodb索引BUG引发的血案

简述

2020.01.21 2:00

做了一个索引优化。将3个索引优化为1个。只保留了一个{session_id, create_timestamp}索引,更到线上后未发现大的问题。

2020.01.24 1:00

发现数据库访问RTT不明原因地升高。触发了限流,部分用户不能登录。因为凌晨的访问量是平时的3-5倍。因为各方面指标都慢慢趋于正常。未做更多处理。

2020.01.24 16:00

午睡时想到凌晨的种种奇怪现象(另一个database的RTT也变高了)。

完全不相干的两个database。CPU没遇到瓶颈,只可能是磁盘IO了。一看磁盘IO吓一跳,居然是满的!(讶异于没有磁盘IO报警,也讶异于索引有不对的地方),mongotop一看。相关table的read/write 都在1Kms级别。

仔细地比较各个操作的rtt时间,发现msg表的update从更新前的1ms内,上涨到了6-7ms。msg表最慢的round trip,没有大的变化。看来是长尾效应导致的问题。

查看代码时发现,在设置消息已读时,正常情况下会在unread_sessions拿到该会话的一个未读create_timestamp,在设置后,会清理掉该create_timestamp。在设置一个无unread的会话时,拿不到时间戳,会向前检索一周的消息。从慢查询日志中发现,有update操作会遍历300多条记录。

之后的fix和更新就不谈了。

总结

任何线上问题的发生都是多个错误综合造成的。总结如下:

监控

  • 磁盘IO报警没有生效。
  • 应用层监控缺乏数据库的整体表现情况。除了关注最坏rtt, 特定接口的rtt,还要关注整体情况。最直观的就是mongotop,磁盘IO使用率,CPU使用率,网络IO使用率。
  • 应监控慢查询的数量,达到一定阈值报警。

灰度

测试机器人和用户表现不一致。需要灰度机制发现问题。

敬畏心

做服务端要细心,动的时候就有点怂。动完应对线上情况做更多观测(当时觉得有任意索引BUG,都会导致整个数据库卡死,10亿规模的表)。

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章