用jdbc连接MySQL时,可能应用的错误日志里经常发现这样的报错:
Communications link failure Last packet sent to the server was **** ms ago
间隙性出现,看起来对业务影响不大,部分同学以为是网络抖动忽略这种间隙性的报错。
先说结论:
这是jdbc的连接池设置和MySQL的设置没有配合好。
1.调整数据库超时时间Wait_timeout
2.调整jdbc配置
两种方式都可以消除这种错误
1.数据库连接池(connection pool)
客户端(jdbc)连接到服务端(MySQL) 时创建了连接,执行SQL,完成以后,这个连接客户端不是断开连接,而是放进连接池里,等下次会话需要时直接访问。这里的连接池可以加快程序访问数据库的速度,提升效率。
对于频繁和数据库交互的应用,用连接池可以很大程度上减少和数据库建立连接的时间。
注意:使用了数据库连接池,在代码里conn.close()方法,在实际意义上只是把这个连接交还给了连接池,和数据库的连接并没有真正断开。
在数据库端show processlist可以看到:sleep的连接,空闲了多少(这张图里0-1710秒)
2.数据库空闲连接超时设置(Wait_timeout)
数据库服务器端,这里有两个问题,保持用户端的连接可以降低用户新建连接的成本,但是对于长时间不活动的连接,也不可以无限等待(sleep),用户连接保持也是有成本的。所以数据库有两个设置项:
show global variables like '%timeout';
wait_timeout 默认值:28800(秒)
interactive_timeout 默认值:28800(秒)
复制
wait_timeout 用来控制jdbc等应用程序连接数据库长时间不活跃MySQL主动断开连接的时间
interactive_timeout 用来控制mysql客户端ide工具连接数据库长时间不活跃MySQL主动断开连接的时间。
两个参数含义一样针对的访问访问不同而已,这里我们只需要关注wait_timeout参数即可
注意:wait_timeout时间到了以后,服务端MySQL断掉连接后,并不会通知(也没法通知)连接池,所以连接池里的连接如果被拿去使用时,就会产生Communications link failure 报错
3.最佳实践:
3.1 MySQL参数设置
wait_timeout :900秒 #通常设置为900秒超时,各业务线可以根据实际情况调整
interactive_timeout :900秒 #建议和wait_timeout保持一致
复制
3.2 jdbc端设置:
jdbc.connection-pool.max-idle-time < wait_timeout
jdbc.connection-pool.idle-test-interval < interactive_timeout
复制
3.3 apache连接池配置
validationQuery = "SELECT 1" 验证连接是否可用,使用的SQL语句
testWhileIdle = "true" 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.
timeBetweenEvictionRunsMillis = "30000" 每30秒运行一次空闲连接回收器
minEvictableIdleTimeMillis = "1800000" 池中的连接空闲30分钟后被回收,默认值就是30分钟。
numTestsPerEvictionRun="5" 在每次空闲连接回收器线程(如果有)运行时检查的连接数量,默认值就是5.
复制
3.4 连接串写法:
对于不能修改jdbc连接池设置的地方或不方便修改的,也可以直接直接在连接串上加上autoReconnect=true 达到连接错误后自动重试的机制。网上有资料说这个参数只针对于MySQL早期版本有效,事实上这种说法不准。跟MySQL版本无关。
jdbc:mysql://my3307.corp.dbop.com:3307/testdb?autoReconnect=true
复制