事件回顾:
数据库版本 : percona MySQL5.7.22
主从同步方式:GTID 模式 + 半同步
因业务需求扩张,我们对目前现有的服务架构进行了拆分,由于后台数据有近一半以上都是通过采集第三方所获取到的 由于采集的量比较大,所以单独有一台服务器用来做采集服务。同时在维护数据库方面的经验不足,导致这次问题出现了两次,最终在第二次排查发现中解决掉的。
第一次:
由于用户反馈后台数据有部分数据没有实时更新,根据经验第一反应就是去采集服务器查看采集是否正常运行。由于采集脚本是放在crond 服务中运行的,起初以为是crond 服务挂了。
通过一下方式排查:
查看定时任务[定时任务是正常运行的]:
systemctl status crond
查看执行脚本转状态[定时任务日志也有正常打印输出]:
tailf /var/log/cron
关键点:手动执行采集脚本,但执行后并登陆数据库查看数据依然没有更新。
再次定位:定位到了数据库服务,并在数据库执行sql语句,发现无法更新数据。
处理方法:由于时间紧迫,当时重启了数据库服务后就恢复了正常。
后续问题排查
由于这次事件,并没有找到导致问题的原因,我调出了当时的服务监控,发现服务在某一时间段开始,所有服务器压力开始逐步上升并没有下降的意思,一直到我接收到问题反馈。
第二次
这次同样接受到后台数据不更新,但我们这次又了新的发现。
无意间查看了采集脚本进程[发现几个进程竟然跑的一个脚本]:
ps -ef |grep php
登陆数据库查看表锁[发现大量表锁信息]:
SHOW OPEN TABLES WHERE In_use > 0;
第一步:停掉在定时任务导致锁表的采集脚本
第二步:查看MySQL进程并kill掉
第三部:手动执行采集脚本并重新打开定时任务。
第二步[查看SQL进程]
SHOW PREOCESSLIST
第二步[kill ID进程]
kill [ID number]
收尾工作:
第一:清理掉所有SQL进程之后并开启定时任务,开始观察MySQL服务是否出现表锁问题。
第二:根据老高建议 让开发打印出SQL语句,并检查WHERE条件是否有添加索引。
第三:发现WHERE条件并没有添加索引,同时给使用WHERE的字段添加索引。
最后总结
由于采集在执行UPDATE操作时,WHERE条件的字段没有索引,当采集的数据是INSERT时是没有任何异常,但如果采集是UPDATE的时候,就会出现全表查询然后更新。而定时任务是每分钟执行,由于采集脚本没有做任何判断,当第一个采集任务没有执行完毕,第二个采集脚本就开始运行了,这样不断累加。而数据库因没有更新完,后面出现大量的SQL的进程阻塞。从而使数据无法正常运行。
预防解决方法:
第一:延长执行采集脚本的间隔时间
第二:监控SQL进程,当出现大量进程时报警
第三:监控SQL表锁信息,超过一定数量时报警。
第四:检查所执行的SQL语句并适量添加索引来提升更新速度。
注:索引是个好东西,但索引过多也会导致性能下降。同时在添加索引的时候我请教一位开发他的建议是索引最多不要超过四个。