线上MySQL挂了,我做了这几件事情立即恢复
给客户做的一个项目上线后数据库挂了,这次轻敌大意了。
去年年底交付的一个项目,今年2月份的某天客户突然打电话过来,说他们的小程序响应特别的慢,页面加载不出来。我尝试了多次确实打不开或者响应极其缓慢,看来不是个例现象,询问客户最近有做什么事情,客户说他们做了一个活动,这几天用户量上来了。
典型的用户量一上来服务就出现性能问题,我挂掉电话开始排查定位问题。
一、线上配置
为了方便大家一起和我复盘这次事故,我尽可能的提供更多一些详细的信息,我给客户整体的部署方案都是上云的,网络拓扑如下图所示:
相关配置如下:
云产品 | 配置 | 说明 |
SLB | 简约型 | 负载均衡 |
ECS | 2C4G | 6台做一个负载均衡 |
Redis | 2G | 主从标准版 |
MySQL | 2C4G | 基础版 ESSD PL1 云盘100G |
这套方案属于省钱版,整体下来算上促销活动一年也就1万多块钱。
二、定位解决问题
出了问题后第一时间我怀疑是部署服务的ECS出问题了,登录到阿里云控制台上发现6台服务器的各项指标都很平稳,CPU、内存都很健康,均在60%水位线以下,只是流量大了点。
这个时候我又去看了一下SLB的访问日志,看看接口的响应情况
* | SELECT status , count(1) FROM log where status > 204 GROUP BY status order by count(1) desc;
查询结果大致如下:
code | count |
499 | 1454 |
504 | 42 |
401 | 35 |
408 | 8 |
发现有大量的499错误码,显然服务端此时的响应整体比较慢。可是服务器的负载、内存都很正常,那什么响应慢呢?我赶紧去查看数据库,发现数据库的CPU早就已经被打满了,持续了十几分钟了。。。
到这里我们已经定位到了是数据库出挂了,那么接下来就是要定位到具体数据库什么地方出问题了。
MySQL出现了性能问题,根据目前的场景以及客户反馈的情况我判断可能有以下几种可能:
- 访问量突然变大导致数据库顶不住;
- 慢查询、大结果集查询把数据库拖死了;
- 有长事务;
但是当时的数据库连接数并不高,才用了不到50%,说明连接是够用的,这点也是可以理解的,因为我给数据库连接池配置的最大链接数是200,6台算下来吃满也才1200连接数,而且看上图中MySQL的内存利用率才50%左右,但是CPU早就100%了,说明要计算的东西多,数据结果集不大。
到这里,基本上可以判断是有慢查询了。
虽然上面说了一大堆,但是排查思路上也就是几分钟的事情,紧接着就去看MySQL的慢查询日志:
发现有好多这样的日志,需要解析的行数18万多,返回的结果就20条,显然这种SQL一看就没走索引,看具体业务是一个排行榜相关的业务,因为前期没有数据量,直接查询的表,也没做索引设计,结果导致数据库CPU直接100%!
找到了具体的问题点,接下来就是修复了,具体措施如下:
1、排行榜接口降级,不走具体查询逻辑,返回固定的数据;
2、扩容MySQL到4C8G,重启MySQL,优先恢复访问;
3、修复错误数据;
4、解决排行榜的问题,因为排行榜实时性要求不高,我们可以不用每次都查询业务表,而且单独做一张排行榜表,业务数据有变更时候异步计算排名数据,同时加入缓存机制;
5、性能优化,根据SLB日志查看所有的接口调用排名,根据频率高低、耗时长短来挨个走查是否存在性能问题,数据库是否有效命中索引,表数据量大不大,是否需要增加缓存等等全方位系统优化;
最终花了2天时间做了一次系统大的优化,优化上线后系统性能明显好转,最直接的体现就是顺利的扛住了客户的活动流量,即使在业务高峰期,服务器、数据库的压力都明显降低,并且稳定运行至今,最终也得到了客户的认可(响应及时、快速解决问题)。
三、MySQL索引常见问题总结
在 MySQL 中,会引发性能问题的查询,基本上都是查询没有有效命中索引所导致,而没有有效命中索引具体又分为两种情况:
1、SQL语句没写好,没有按照创建的索引规则来写
2、索引设计的不好
SQL语句没写好导致索引失效是大家比较常见的一种情况,日常工作中也比较容易犯错:
- 左模糊查询:like %xxx;
- 含有关键字 or、<>、!=、not in、not exist等等;
- 函数计算 where DATE(create_time) = '2023-04-25';
- 索引列参与运算 where num + 1 = 10;
- 类型不一致,例如name字段是varchar类型,查询语句为where name = 18;
- 联合索引没遵循最左匹配原则。
索引设计的不好也是SQL调优的重灾区,常见的有:
- 能走覆盖索引的没走覆盖索引;
- 索引区分度设计不好,导致mysql认为走索引还不如走全表扫描;
- 没有很好的利用索引下推机制;
- 一张表设计了太多的索引;
- 索引上的字段有null值;
以上只是总结了一些常见的错误,实际开发中由于业务的复杂性,很多SQL大家并不能一眼就能看出来到底有没有走索引,有没有走合适的索引,强烈建议大家在写SQL时候优先使用EXPLAIN来查看SQL语句的执行计划来综合评估,从而写出最佳SQL。
你还知道日常开发中关于数据库方面哪些容易犯的错误?欢迎评论区留言讨论~
感谢各位点赞、收藏、转发、关注,持续为您分享优质内容!