华为云RDS数据库连接池调优,一次接口响应时间从800ms降到120ms的实践
我们有个供应链管理后台,业务量一直挺平稳的,直到上个月接了个新客户,单日订单量翻了四倍。上线第三天,运营开始反馈页面加载变慢,导出报表直接超时。看了一眼APM监控,接口平均响应时间从原来的150ms涨到了800ms,数据库连接等待时间占了将近500ms。
第一反应是数据库扛不住了,登录华为云RDS控制台看监控,CPU 35%,内存60%,连接数200出头,离上限还远得很。慢查询日志翻了一遍,也没发现什么特别慢的SQL。那问题就出在应用侧了,应该是连接池不够用,请求都在排队等连接。
我们用的Spring Boot,默认连接池是HikariCP,配置一直用的默认值:maximumPoolSize=10。平时并发低,10个连接绰绰有余。现在并发上来了,连接不够分,大量请求阻塞在获取连接这一步,响应时间自然就上去了。
先把maximumPoolSize从10调到50,重启应用,观察了半小时,响应时间降到了300ms左右,效果明显但没有完全解决问题。再次查看监控,发现连接池的实际使用量峰值到了35左右,说明50个连接够用,但响应时间没回到150ms的水平,说明还有其他瓶颈。
又检查了数据库连接的超时时间,HikariCP默认的connectionTimeout是30秒,这个没问题。但idleTimeout是10分钟,maxLifetime是30分钟,意味着连接被复用后,如果执行了慢SQL,会长时间占用连接不放,其他请求只能排队。我们的查询业务虽然单条SQL不慢,但每次请求会查询多个表,整个事务耗时累积下来,连接的周转速度就慢了。
调整了HikariCP的几个参数:
最大连接数保持50,因为监控显示峰值35左右留了余量。
连接超时从30秒降到5秒,如果5秒拿不到连接就直接报错,快速失败比让用户傻等强。
闲置超时从10分钟降到5分钟,让空闲连接更快释放。
最大生命周期从30分钟降到15分钟,避免连接被用太久导致数据库端连接失效。
加了一个关键配置:keepaliveTime=30秒,HikariCP会定期发送心跳检测连接是否存活,避免从池子里拿到一个已经被数据库端关闭的连接。
还有一个容易被忽视的点,Spring Boot的DataSource配置里,默认的validationQuery是空的,如果不配的话,连接池不会在借用连接时做校验。我在配置里加上了:
spring.datasource.hikari.validation-timeout=5000
spring.datasource.hikari.leak-detection-threshold=60000
leak-detection-threshold这个参数特别有用,如果连接被持有超过60秒,日志里会打印警告,帮我们找出哪些业务代码持有连接时间过长。
改完配置重启后,观察了一整天,响应时间稳定在120ms到150ms之间,连接池使用量峰值降到了25左右,说明连接周转变快了,实际需要的连接数反而减少了。
后面排查代码时发现,有个订单导出功能里,MyBatis的ResultMap配置了嵌套查询,每查一条主记录就额外执行好几条子查询,N+1问题导致单次请求持有连接的时间特别长。把这个改成分步查询后,单次请求的数据库操作时间从800ms降到了50ms,连接池的压力进一步降低。
总结这次调优的经验:连接池大小不是越大越好,关键是要让连接快进快出。调大池子只是第一步,真正要解决的是连接持有的时间。搭配leak-detection查出长时间占用连接的代码,配合合理的超时和心跳配置,才能让连接池在高并发下稳定工作。
现在这套配置跑了两个月,没有再出现过连接等待导致的响应延迟。
- 点赞
- 收藏
- 关注作者
评论(0)