案例分享:mysql代理引起的Unable to acquire JDBC Connection问题。

IT疑难杂症诊疗室 10w+人浏览 693人参与

问题背景

朋友们大家好,今天分享一个小案例,

收到项目现场反馈,部署的程序异常,无法使用。 通过查询日志发现出现 “Unable to acquire JDBC Connection”的报错。

简单来说,“Unable to acquire JDBC Connection” 就是程序想连数据库,但没拿到连接。
在这里插入图片描述

问题分析

  1. 首先查看数据库状态,数据库服务指标正常,连接数据库也正常。

  2. 因为我们的应用使用的是HikariCP连接池。所以检查下HikariCP。

# HikariCP示例配置:
spring.datasource.hikari.maximum-pool-size=10  # 最大连接数(避免过小)
spring.datasource.hikari.connection-timeout=30000  # 连接超时时间(ms)
spring.datasource.hikari.idle-timeout=600000  # 空闲连接超时
spring.datasource.hikari.max-lifetime=1800000  # 连接最大存活时间

HikariCP 作为高性能 JDBC 连接池,核心作用是复用数据库连接、减少连接创建销毁开销,同时通过高效管理提升数据库访问性能与可靠性,简化连接获取流程并保障高并发场景下的连接可用性。
从 HikariCP 角度分析 “Unable to acquire JDBC Connection” 报错(数据库服务正常时),需重点排查这几个方面:

一、 连接池资源耗尽

  1. 连接池配置不合理,

一般是maximum-pool-size设置小于业务并发需求,导致连接池达到上限后无法分配新连接。

  1. 连接泄漏,

应用未正确释放连接(如Connection未在finally中关闭),导致连接池被占满,新请求无法获取连接。

查看日志中是否有LEAK DETECTED信息,定位未释放连接的代码位置

二、 连接有效性问题

  1. 连接超时或失效

数据库端关闭空闲连接(如 MySQL 的wait_timeout默认 8 小时),但 HikariCP 未检测到,分配了失效连接

检查数据库超时配置:

SHOW VARIABLES LIKE 'wait_timeout';  -- MySQL
  1. 连接创建超时

connection-timeout过短,数据库响应慢时无法在超时时间内创建连接
排查:日志中包含Timeout after xxxms of waiting for a connection。

怀疑对象

根据现场的分析排查,以上问题都不太符合(这里其实是结论下早了)。但是再查看服务数据源配置的时候发现一个可疑的地方,服务配置的数据库连接信息不是直连的数据库地址,配置的是 Azure Load Balancer地址。

Azure Load Balancer 有一个 默认“idle timeout” 4 minutes 的配置。 这个比较坑,这是官方解释。

In its default configuration, Azure Load Balancer has an ‘idle timeout’ setting of 4 minutes.
This means that if you have a period of inactivity on your tcp or http sessions for more than the timeout value, there is no guarantee to have the connection maintained between the client and your service.
When the connection is closed, your client application will get an error message like “The underlying connection was closed: A connection that was expected to be kept alive was closed by the server”.

原文链接:https://azure.microsoft.com/en-us/blog/new-configurable-idle-timeout-for-azure-load-balancer/

说白了就是:如果你的 TCP 或 HTTP 连接搁那儿 “摸鱼”—— 超过 4 分钟没任何数据传输,那客户端和服务器之间的连接就可能被断开(官方说 “不保证维持”,实际场景里基本都会断)。
等这连接一断,你的客户端程序就会报个错,大概意思是:“底层连接被关了啊!本来以为能一直连着的,结果被服务器给掐了~”

原因分析

达到了Load Balancer 的空闲连接限制(4 minutes), 触发了 Load Balancer 的连接回收, 但是被Load Balancer 中断的连接, 应用程序未能正常进行回收, 导致程序拿到了已经失活的连接, 从而出现该问题。

应用连接池创建的到数据库的连接, 如果是直连的情况一般是看mysql的wait_timeout 配置(maxLifetime 小于数据库的wait_timeout),但是我们这里加了一层 Load Balancer 这里就需要考虑配置 (maxLifetime 小于4 minutes)

但是修改maxLifetime 太短显然不合理,但是Azure Load Balance 还是可以配置的。

将 Load Balancer 的空闲连接探测时间调整为 30 分钟后,有运行观察了一段时间,问题有所改善。也算是解决了。

知识点整理

Mysql wait_timeout

MySQL会将超过一定时间的空闲连接主动关闭,以清理出资源支持其他活跃连接。在MySQL中有一个参数wait_timeout,用来指定Mysql关闭非交互空闲连接之前秒数。
我们可以执行show variables like 'wait_timeout%'来查看该参数

官方重点强调

在 HikariCP 的 github 官网也有 maxLifetime 设置的暗示:

This property controls the maximum lifetime of a connection in the pool. An in-use connection will never be retired, only when it is closed will it then be removed. On a connection-by-connection basis, minor negative attenuation is applied to avoid mass-extinction in the pool. We strongly recommend setting this value, and it should be several seconds shorter than any database or infrastructure imposed connection time limit. A value of 0 indicates no maximum lifetime (infinite lifetime), subject of course to the idleTimeout setting. The minimum allowed value is 30000ms (30 seconds). Default: 1800000 (30 minutes)

hikari强烈建议设置该值,该值需要比数据库或者基础设施(划重点)的(空闲)连接时间限制要短一点。默认值30分钟。

HikariCP核心配置参数整理

参数名作用及默认值建议配置
driverClassNameJDBC驱动类名(HikariCP可自动检测,非必填)MySQL 8.x:com.mysql.cj.jdbc.Driver;MySQL 5.x:com.mysql.jdbc.Driver
maximumPoolSize连接池最大连接数(默认10)根据数据库规格调整(如MySQL默认最大连接数151,建议设为20-50)
minimumIdle最小空闲连接数(默认与maximumPoolSize相同,建议保持默认)无需手动修改,HikariCP会自动管理
connectionTimeout获取连接超时时间(默认30000ms/30秒)按需调整,避免过短导致频繁超时
idleTimeout空闲连接超时时间(默认600000ms/10分钟,0表示禁用)需小于maxLifetime
maxLifetime连接最大生命周期(默认1800000ms/30分钟)需小于数据库wait_timeout 或者 基础设施 建议设为30分钟
leakDetectionThreshold连接泄露检测阈值(默认0/禁用,单位ms)调试时设为30000(30秒),生产环境建议禁用或设为更高(如60000)
connectionTestQuery连接有效性测试SQL(JDBC4+可留空,自动用isValid()MySQL:SELECT 1;PostgreSQL:SELECT 1
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值