托尔斯泰:“幸福的家庭总是相似的,而不幸的家庭则各有各的不幸。”
mysql崩溃会导致整个系统的崩溃,也就是P0级别的生产事故。而mysql崩溃的原因各有不同,这里分析一种业务场景:
mysql环境:读写分离。
项目环境:微服务体系。
1. 技术背景
-
一个比较复杂sql在90%的场景下并不是慢sql,上线前无论分析explain还是profile,均显示这个sql并没有问题。但是当这个sql查询出海量的数据,那么它会在
sending data
占用太多的时间。导致慢sql。 -
目前主流的监控手段是监控mysql的慢sql,但是经历过mysql事故的人都明白,当mysql真正出现问题的时候,连
select id from table where id=1
这种sql都是慢sql,都会在监控平台上显示。根本原因是:mysql没有数据库连接。无法快速定位那一个sql才是真正的罪魁祸首。
2. 侦探—mysql崩溃的凶手
你无法知道一个程序员会写出什么代码,正如他也不知道这个代码是不是一个隐患。
前文说到,mysql由于是读写分离架构,那么主库只提供写操作,读操作在从库完成。
1. 风云突起:一天下午,系统突然崩溃,监控平台上都是慢sql。无法在监控平台上定位始作俑者。
2. 求助DBA:出现问题的第一时间,联系DBA。为了系统快速恢复,DBA登上mysql服务器后,将一些疑似的信息发送给我们,然后快速kill掉慢sql。
3. DBA回复:DBA查询出一个高频的DML语句,发现其上有意向锁,以为可能是这个问题。
4. 陷入误区:当时以为是某个表由于“死锁”的问题,导致数据库大量链接被阻塞,从而导致项目所有的sql都被阻塞,导致系统崩溃。
但是关注我的老粉丝都知道:MySql性能(4)-mysql锁知多少(表/行锁、共享读锁/独占写锁、共享锁/排他锁、间隙锁、意念锁)
意向锁:是Innodb为了处理表锁和行锁的关系,而自动为行锁加上一个一个“伪表锁”。目的是:当一个表加上行锁后,在对这个表加表锁,表锁会发现存在一个“伪表锁”即意向锁,而直接等待。
5. 另辟蹊径:但是我并不以为是易向锁的问题,并且结合dba给出的问题,我也不以为是DML语句造成死锁从而引起mysql崩溃。打开skywalking的链路追踪,查询系统第一次出现慢接口的sql情况。发现有大量的并发sql(代码有线程池)查询主库。
6. 疑点分析:对sql执行explain和profile(当然不是原有的参数,因为skywalking只显示2048个),发现这个sql并不是一个慢sql。
为什么只显示2048个字符,原因是agent有一段代码进行截取,当然我们可以修改这块代码,然后对插件重新打包。skywalking(2)自定义插件【okhttp插件-监控cos的sdk调用】
7. 陷入僵局:无法查询出什么原因导致mysql崩溃。
8. 危机再现:过了一天,mysql再次崩溃,登录skywalking后查询第一个慢接口中的sql信息,发现和昨天一样,依旧是同一个接口,同一个sql。
9. 逐渐明朗:这不是巧合。并且再次求助DBA,DBA说mysql服务器中存在大量的这个sql。我们分析了下业务,发现这个sql是可以直接被kill掉的,当kill掉这个sql后,系统恢复。
10. 真相只有一个:这个sql表面上看并不是一个慢sql,甚至90%的场景下,都不是一个慢sql,但是由于这块业务的复杂性,这个sql针对某些参数,查询出大量的数据,关键是并发查询的主库。导致数据库连接被大量占用,影响项目的其他业务。
3. 是否需要mysql监控大对象?
写一个mybatis的插件,分析sql查询出的对象大小,然后通过订阅发布的方式报警。
这样,当mysql崩溃时,可以在另一个角度来分析是不是并发查询出大量数据造成的mysql崩溃。
mysql大对象插件还有一个好处是:当高峰期mysql某些sql查询出大量数据,可能引发OOM。
故使用mysql大对象插件,可以有效预防这种sql而导致的系统崩溃。
4. 经验教训
- 读写分离,主库最好不要存在读操作。
- 最好的意思:因为存在主从延迟情况,有些业务场景是需要查询主库的。
- 可以对mysql大对象维度进行监控和报警。
网友评论