记一次mysql数据生产事件。那是一个风和日丽的下午,应用一直像短跑运动员一样跑动,突然在下午2点30分的时候,变成了像得了帕金森的老头一样,持续慢了一下午。第二天又像什么没发生过一样,重回短跑健将的状态,正常运行一直持续到现在。问题就是这样一个问题,当看到这个问题时你第一时间是怎么想的那?????问问自己该咋整。。。。
基础信息:数据Mysql5.7、调度模块应用(springboot、线程池技术)、生产环境20个pod、数据库的隔离级别rc级别;
简单介绍一下应用的执行逻辑:1、将任务数据写入数据库中;2、应用根据任务状态获取可执行的任务,将任务丢入线程池中,执行调度任务;3、每天有500万的数据量调度执行。
这时你肯定会想,怎么保证任务执行过程中不会出现重复执行,先介绍一下我们的实现:对数据进行分片和使用数据排他锁(for update),保证了任务同时被调度且相互之间不争抢,调度速率刚刚的。。。。。。
按照正常逻辑分析,这样的情况下数据库一天时间支撑个300万的调度很轻松,cpu也不会很高(前提是只有一个应用在使用数库)
言归正传,当我们看到数据库突然变慢,并持续了很久。能想到的两种情况:
第一种cpu高导致数据库性能下降;
第二种数据库服务器本身出了问题;
这两种情况比较好区分,登录数据库服务器使用top命令,查看服务器cpu情况,判断是否mysql的cpu过高导致,如果不是mysql导致,需要看一下是哪个程序导致服务器cpu过高,找运维同事一起定位排查解决,这种情况一般不会有。如果是mysql程序本身cpu占用非常高,持续为99%,这种情况就属于数据库的问题,一般造成mysql数据库cpu飙升问题有两类 一类是数据库上很多慢sql执行导致数据库执行效率降低,cpu飙升; 一类是数据库并发数过高(qps过高),导致数据压力过大出现cpu飙升;
如何区分这两类问题?
1、查看慢sql日志、error日志 :看一下慢sql有哪些(首先查看一下数据库中配置的慢sql日志查询时长show variables like ‘%long_query%’ 该参数为查询时长超过多少秒时为慢sql)、错误日志中是否有死锁或锁等待超时情况(搜索deadlock或timeout)
2、show full processlist ;查看当前数据执行情况,哪些程序执行时间较长;
3、show status like ‘%Thread%’ ;查看当前数据库有多少个线程连接,判断当前数据库的并发情况,是否达到最大连接数(可以通过show variables like ‘%max_conn%’);
一般通过以上步骤就可以区分出导致cpu冲高的原因是哪一类原因导致的,首先我这次出现的问题是慢sql导致cpu冲高。
看到这里大家肯定回想,这么简单的问题还拿出来说,给你两大嘴巴子。。。我的问题主要是为什么同样的sql语句,已经运行了好几个月都没问题,突然有一天告诉我它是慢sql,这不合天理,绞尽脑汁也没想出原因(我们的数据量没有大幅度增加,每天都是300万左右),让人头疼的事情就是为什么,开始的时候好好的,结果。。。。。。
我们一开始分析从sql的执行计划和数据分布入手,因为最近没改过相关代码,不应该是代码的问题。那不是代码的问题,那就是数据的问题。分析步骤大概如下:
1、explain 加sql查询sql的执行计划,最好是在生产环境中跑一下执行计划,这样更准确,因为测试环境的数据分布及数据量可能不一致,从而导致执行计划不同,sql的执行效率不一样。比如测试环境完美无缺,生产环境垃圾到家。
2、查看数据库的索引字段show index from 表名;根据索引字段对应的值进行分组统计一下数据库中的不同值的数据占比;因为数据量的不同会导致执行计划走的索引不同。
经过这两操作我得出了结论,执行计划上午走A索引、下午走B索引;在生产上强制指定了一下索引,返现A索引比B索引查询效率高一些。但是之前应用也是这样跑的,为啥没出现cpu过高,慢sql等情况。
通过不懈努力的寻找,问题原因找到了,倒置cpu过高的原因是因为慢sql过多(我们有一个补偿机制的sql执行太慢,而且执行批次较大),慢sql过多导致数据库cup冲高;有个比较隐蔽的问题就出现慢sql的sql语句,并不是一整天都慢,而是下午慢,下午慢的原因是因为我们有张表在经过一段时间后数据状态分布不均匀,下午执行sql时mysql优化器改变了sql的执行计划,走了不一样的索引,导致扫描行数据剧增,查询效率下降。
问题找到了,该怎么解决那???
首先我们解决慢sql最直接的方法就是优化sql,或者降低sql的执行频次;
(1)我们优化了sql的索引,即sql语句
(2)我们使用分布式锁(redis实现)降低sql的执行频次;
通过以上两个步骤,cpu很稳定,再没有冲高过。
总结:遇到问题一定要从问题本身出发,反向推理,多问自己为什么???不要把简单问题复杂化,根据可能导致问题的原因进行分类验证,快速定位明确问题,然后再想办法解决问题。千万不要问题原因还没弄清楚就乱猜想,直接就想办法解决,这样会导致越改越乱,事倍功半。