mysql SQLNonTransientConnectionException 异常分析处理

问题描述:

线上某个业务在运行时突然抛出这么一个异常信息:

java.sql.SQLNonTransientConnectionException: (conn=328473) unexpected end of stream, read 0 bytes from 4 (socket was closed by server)
at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.get(ExceptionMapper.java:240)
at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.getException(ExceptionMapper.java:171)
at org.mariadb.jdbc.MariaDbStatement.executeExceptionEpilogue(MariaDbStatement.java:248)
at org.mariadb.jdbc.ClientSidePreparedStatement.executeInternal(ClientSidePreparedStatement.java:230)
at org.mariadb.jdbc.ClientSidePreparedStatement.execute(ClientSidePreparedStatement.java:157)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:198)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:198)


原因分析:

【1】线上某个操作突然抛出这个异常,因为之前没出现过,首先第一反应是不是网络抖动问题导致的超时而衍生出的问题.

【2】把数据库的连接都改为了内网访问,发现还是会出现。
【3】怀疑是连接池配置问题,怀疑是不是从连接池中获取到的连接有问题,于是改了连接池的 test-on-borrow: true (从池中取连接时校验当前链接是否可用)、
test-on-return: true (把连接放回池中时校验是否可用)、 test-while-idle: true (开启验证连接的有效性) ,time-between-eviction-runs-millis: 6000 (空闲连接的回收间隔时间 ,这个与test-while-idle搭配使用,即每隔6秒钟把空闲的连接进行回收) 。通过这一步,确保连接池的连接是可用的。发现还是出现这个异常。
【4】叫开发人员去看看这一块的业务逻辑,发现有个大事务的操作。
【5】最后还是锁定在SQLNonTransientConnectionException 这个异常上。然后查看了一下数据库中的一些参数配置,然后发现了这么个东东:innodb_lock_wait_timeout , 默认值为 50秒 , 意思是一旦数据库锁超过这个时间,就会报错。
mysql SQLNonTransientConnectionException 异常分析处理_第1张图片

【6】再把日志文件拿下来,查看了一下这个带事务的业务逻辑执行完的一个时间跨度,发现执行了60多秒(里面有一些发消息的动作,都是用同步操作,还有一些sleep睡眠时间,,所以在执行最后一个update操作的时候,这个事务(锁)占用的时间已经是超过了innodb_lock_wait_timeout指定的50秒)
【7】校验重现问题:在备环境中减少这个业务逻辑的步骤,比如之前出问题是6个步骤,现在改成3-4个 , 执行测试,50秒内执行完成,后台也不会报错,正常。然后再把步骤增加到5-6个以上,发现都需要在50+秒以上才执行完,也是在最后一个update要执行时抛出这个异常。


解决方案:

改代码,把一些业务外的弄成异步,优化执行的sql , 更新上线,over~

你可能感兴趣的:(mysql)