记一次线上故障

运行一个星期好好的,突然到了周一APP运行缓慢,并且有用户已经卡在欢迎页面。接到消息心里咯噔了一下:很有可能是并发引起的性能问题。于是第一时间叫DBA看应用服务器和数据库服务器的资源使用情况,应用服务器和数据库服务器资源使用情况都在正常范围内,很是奇怪。然后只能从应用本身着手了。

tail了下日志,发现日志一直在刷着异常信息:Pool empty. Unable to fetch a connection in 30 seconds, none available[size:100; busy:100; idle:0; lastwait:30000]。看异常比较明显是tomcat的连接池用完了,第一反应是把连接池配大:spring.datasource.tomcat.max-active=200。把数据库的连接数调整到了500,结果不出所料,过一会200也用完了:Caused by: org.apache.tomcat.jdbc.pool.PoolExhaustedException: [http-nio-7001-exec-11] Timeout: Pool empty. Unable to fetch a connection in 6 seconds, none available[size:200; busy:199; idle:0; lastwait:6000]。

与上一次不同的是数据库则抛出User sltapp already has more than 'max_user_connections' active connections。也就是这次数据库的最大连接数也不够了。现在检查应用服务器和数据库服务器资源使用情况时。应用服务器资源正常,说明加大连接线可以承受的住,数据库的资源却达到85%以上。说明数据库服务器已经有了压力。

接下来我们分析数据库,用SHOW FULL PROCESSLIST快照的方式每5秒刷一下进程列表,发现列表这两个语句在长时间运行着,最高有达到80多秒。杀掉之前马上又上来了。可以确定是由于这两个语句长时间查询把连接数占满了。

找到原因之后,开始对这SQL动刀子了。经分析该语句为了取子表不同推单状态进行了四次自关联,而且还是大表,还关联了其他大表,问题比较大。最后的方案是SQL只查主表,推单状态在查出主表后,再通过查出来的主表主键查出对应的子表信息,然后把状态标识出来。也就是把复杂的语句简单化,步骤化,然后在JAVA里做逻辑处理。经过一番处理后,性能一下提升到0.几秒就可能把整个结果查询出来。

处理好后测试增量上线,运行一天后,结果挺明显,系统已经不再卡顿,比以前也快了很多。该次事故主要有两个原因:一个是并发数量上来;二是业务数据上来导致原来的SQL执行效率低下。第一点的话可以考虑增加硬件资源和连接数,但这个还不是本质问题,需要从慢SQL着手。

猜你喜欢

转载自blog.csdn.net/tinalucky/article/details/118098980
今日推荐