mysql数据库连接泄露

目录

1、问题暴露

2、造成影响

3、紧急抢救

4、原因分析

5、最终解决

这几天公司业务突然陡然增长,日活量增大,一天有五万请求量,长久以来的服务,日志容量从40MB 突然增长到170MB,我马上意识到不妙。

没有耐心的同学可以直接跳到第5步。

1、问题暴露

 首先发现日志记录异常,只提取重要信息记录如下:

大致意思是数据库连接不可用,连接超时

2025-05-17 14:45:30 ERROR http-nio--exec-30 *****.GlobalExceptionHandler 系统内部异常,异常信息
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLTransientConnectionException: base - Connection is not available, request timed out after 30000ms.
### The error may exist in ***************************/RecordMapper.java (best guess)
### The error may involve *****************************.RecordMapper.insert
### The error occurred while executing an update
### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLTransientConnectionException: base - Connection is not available, request timed out after 30000ms.
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:97)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:439)
    at jdk.proxy2/jdk.proxy2.$Proxy143.insert(Unknown Source)
    at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:272)
    at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:59)
    at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:152)
    at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
    at jdk.proxy2/jdk.proxy2.$Proxy144.insert(Unknown Source)
    at com.baomidou.mybatisplus.extension.service.IService.save(IService.java:60)
    at cc.mrbird.febs.ah.service.impl.RecordServiceImpl.createRecord(RecordServiceImpl.java:160)
    at cc.mrbird.febs.ah.service.impl.RecordServiceImpl.receiveBillingResult(RecordServiceImpl.java:248)

2、造成影响

直接造成部分数据丢失,当天晚上同事就联系我说,数据有丢失,还好日志里有全部信息,只是在入库时造成部分数据丢失。可以采取补救措施。

3、相关代码

相关代码也很简单就一两行,用的还是mybaits-plus,确实没什么可讲的

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createRecord(Record record) {
//        this.save(record);
        recordMapper.insert(record);
    }

4、紧急抢救

问题出现了,马上采取补救措施,先是排查问题,意识到是数据连接出现了问题,数据量太大,影响插入,此时还没意识到是连接泄露,先是增加了连接时长,以及连接数量,相关信息增加如下:

spring:
  datasource:
    dynamic:
      hikari:
        connection-timeout: 60000     # 获取连接超时时间(默认30秒)
        validation-timeout: 5000      # 添加连接有效性检查超时(建议5秒)
        max-lifetime: 1800000        # 连接最大存活时间(默认30分钟)
        maximum-pool-size: 60        # 最大连接数(需根据压测调整)
        minimum-idle: 15             # 最小空闲连接(建议与 max 一致避免扩容延迟)
        idle-timeout: 60000          # 空闲连接超时释放时间(默认10分钟)
        leak-detection-threshold: 30000  # 连接泄漏检测阈值(30秒)
        connection-test-query: select 1 from dual  # 明确测试语句(Oracle需调整)

然后重启应用,登录数据库,使用命令查看连接信息

-- MySQL
SHOW STATUS LIKE 'Threads_connected';  -- 当前活跃连接数
SHOW VARIABLES LIKE 'max_connections'; -- 最大允许连接数

-- MySQL
SHOW PROCESSLIST; -- 查看所有连接的来源和状态

这时应用已经重启了,服务竟然也恢复正常了,让我大意了,没注意到,此时连接全在updating 状态,且连接数没有任何增长。因为此时日志也不报错,就此我以为问题就解决了。结果晚上11点以后问题又复现了,第二天早上数据量少的时候,业务又恢复了。

5、原因分析

第二天又被催着去了趟公司,因为这个问题肯定是因为日活太高造成的,之前公司业务量少,都很正常,现在表数量已经到200万条,像这种日活特别高的场景也不是很多见,不是太别想搞。无奈又被催着去公司再看看。

到了公司以后,先是开启慢sql 日志,果然发现其中一条屎山代码,本可以一步插入解决的事,当时的方案是先插入在进行更新,因为是祖传的,其实我很早就注意到这个逻辑了,但是本着能跑就不动代码的原则,我也没动。而原因就出在此处,并发量少的时候,毫无问题,当数据量高的时候,更新查询时间超时,数据库连接泄露,数据丢失。

-- 查看是否开启慢查询日志(ON/OFF)
SHOW VARIABLES LIKE 'slow_query_log';

-- 查看慢查询阈值(单位:秒,默认10秒)
SHOW VARIABLES LIKE 'long_query_time';

-- 查看慢查询日志文件路径
SHOW VARIABLES LIKE 'slow_query_log_file';

-- 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';

-- 设置慢查询阈值(例如:1秒)
SET GLOBAL long_query_time = 1;

-- 记录未使用索引的查询(可选)
SET GLOBAL log_queries_not_using_indexes = 'ON';

-- 关闭慢查询日志
SET GLOBAL slow_query_log = 'OFF';

-- 检查慢查询日志状态(应为 OFF)
SHOW VARIABLES LIKE 'slow_query_log';

开启后记得关闭,否则影响性能。

慢sql 记录如下,因为慢sql 造成了连接泄露,造成普通的更新需要16秒多,这显然很有问题

UPDATE  ah_****   SET imsi='999999999999999',*****       WHERE  (id = '2025051810169' AND phone_number = '15015472379');
# Time: 2025-05-18T09:01:32.903231Z
# User@Host: debian*** @ localhost [127.0.0.1]  Id: 24**
# Query_time: 16.222893  Lock_time: 0.000004 Rows_sent: 1  Rows_examined: 39***
SET timestamp=1747558892;

6、最终解决

找到问题,就好解决了,为慢sql 加了个复合索引,其他受影响的sql 也正常了。

-- MySQL
ALTER TABLE record_table ADD INDEX idx_id_phonenumber (id, phone_number);

业务也恢复了,其他一正常了。此时我再次查看数据库的连接状态,此时数据库的连接状态都是sleep,连接数15 个 。恢复正常了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值