背景

系统上线完成后,一开始运行正常,过了一会儿开始出现:系统所有接口陆续出现长时间无响应或直接响应500。

排查过程

  1. check日志发现数据库连接池连接超时,初步怀疑有连接一直占用连接未释放,通过日志排查了一会,无果。

  1. 暂时先重启服务器

系统恢复了,但是过了一会又开始出现系统无响应的情况,不过发现某些接口可以正常访问,最后排查到在某一段时间除了一个接口无响应,其他接口都可以正常响应。

  1. 定位错误接口

排查日志,发现这个接口在执行一个sql查询后,之后的日志一直没有打出来,怀疑是这个sql的问题,确实,这是一个包含了很多张表join的大sql,在线上试了下,一直跑不出来。

  1. 解决:先将这句sql回滚,保证不拖垮整个系统,再进行后期优化。

具体的sql优化我没跟,但是注意到另一个问题

事故总结

某大sql一直跑不出来,导致数据库连接池连接一直每占用,得不到释放,在频繁访问接口以致频繁触发大sql的情况下,很快将连接池占满,导致后续其他接口无法获取数据库连接,无法响应。这也解释了为什么一开始某些接口还能响应,到最后都不能响应了。

优化

除了sql优化这块,还注意到另一个问题,sql执行超时时间。

  1. sql执行超时时间

通常,系统会设置一个sql执行超时时间,当在超时时间内sql还未执行完成就会中断执行,释放连接,避免因为数据库连接瓶颈拖垮整个应用。拿我们的场景来讲,一段时间内数据库连接池被占满,暂时不可用,但过一段时间后,大sql会执行超时,会自动释放连接,连接池又有可用的连接了,所以一段时间后,系统应该恢复才对,但是我们的情况是系统一直没有恢复。

b. check系统的配置

db server端(mysql):max_execution_time = 0 ==> sql执行时间无限长

应用端sql执行超时配置:无

c. 优化(以下三种亲测有效,根据实际情况选用)

DB server端(mysql):设置max_execution_time来控制sql执行的超时时间,但会影响所有连接到该db的执行时长,影响太大,不建议。

应用端:设置单条sql执行的超时时长,以mybatis举例(单位为秒):

xml:

注解:@Options(timeout = 10)

应用端:设置整个应用所有sql执行的超时时长(单位s)

mybatis-plus:configuration:default-statement-timeout: 60

尝试去找到sql执行超时也踩了一些坑(找错参数)

mysql: connect_timeout, wait_timeout, interactive_timeout

hikari: connection-timeout, max-lifetime(之前一直在往连接池的超时配置上找参数)

不一一总结了。

附:

数据库连接池:Hikari

DB:Mysql

ORM框架:mybatis

参考:

如何配置MySQL数据库超时设置 – 程序员大本营 (pianshen.com)

Mybatis plus设置数据库连超时并抛出异常-后端-风启落时 (bemhome.com)

记一次数据库查询超时优化问题 – 潜行前行 – 博客园 (cnblogs.com)