结论数据库连接数突增是数据库连接资源没有及时释放。
连接数据库超时是因为数据库连接资源释放的过早。
现象1:每次上线项目DB的连接数会突增。
原因:是项目关闭的时候没有释放连接资源导致。
DB的connection资源没有正常释放,导致项目启动的时候再次创建数据库连接资源,就出现了连接数突增的现象。一段时间后mysql根据wait_time的配置,自动回收conncetion,所以连接数又回落回来。
如果是是DB的connection资源没有正常释放,最可能的是在项目关闭的时候没有释放掉DB的连接资源。
经过在查看线上jekins的上线脚本后,发现线上停止项目使用的kill进程的方式来停止项目。那么就证明假设都成立了。接下来解决问题环节(程序员们喜闻乐见的百度和谷歌环节了)。
解决方案。
1.主动释放
项目关闭使用正确的stop命令,保证项目能正确的释放掉各种资源。
执行命令:xxxx_tomcat.stop
2.被动释放
主要目的是尽可能的在新项目上线的同时,mysql自己就回收了连接资源。
如下两个配置搭配服用效果最佳
1.JDBC探活:每隔一段时间唤醒连接,保持长连接。
2.减少连接池内连接生存周期:
2.1 使之小于mysql设置中的wait_timeout的值
2.2 大于配置的探活的周期
2.3 小于新项目上线的耗时,就可以在新项目上线过程中mysql自己回收连接资源避免连接突增的现象的发生。
现象2:连接数据库超时。
com.mysql.jdbc.CommunicationsException:
The last packet successfully received from the server was58129 seconds ago.
The last packet sent successfully to the server was 58129 seconds ago,
which is longer than the server configured value of 'wait_timeout'.
You should consider either expiring and/or testing connection validity before
use in your application, increasing the server configured values for
client timeouts, or using the Connector/J
connection property 'autoReconnect=true' to avoid this problem. mysql
问题原因 :连接池里的connection资源mysql主动提前释放导致。
原因是在datasource连接池中配置的最大空闲时间到达之前(比如maxIdleTime,不通数据源配置名不一样),已经到达mysql的wait_timeout(最大空闲时间),是mysql主动把connection资源回收。但是项目中的连接池还持有connection,所以当项目中使用connection的时候会报CommunicationsException错误。
解决方案
1.修改mysql的wait_time,interactive_timeout把值调大(不建议如果太大,可能导致连接数较多,引起性能下降)
修改配置my.inf文件
或者
mysql命令
set global interactive_timeout = 28800;
set global interactive_timeout = 28800;
2.配置JDBC的重连机制autoReconnect(不建议,只有4.x版本,起作用)
jdbc:mysql://localhost:3306/test?user=root&password=&autoReconnect=true
3.减少连接池内的存活时间+JDBC探活(建议,搭配使用效果好)
JDBC探活:每隔一段时间唤醒连接,从而保持长连接
JDBC减少连接池内连接生存周期,**小于mysql配置wait_timeout 的值(很重要)***
最大闲置资源时间的配置
两个现象的解决方案都指向了同一个配置就是connection的最大闲置资源时间。
有两个地方可以配置最大闲置资源时间:
1.在项目的连接池中配置,比如maxIdleTime。
2.在mysql中也可以配置,interactive_timeout和wait_timeout。
三、MySql中的connection超时配置
mysql的配置中有interactive_timeout和wait_timeout两个参数,这两个参数有时候还存在覆盖的关系,所以还是给大伙说清楚一点两个的区别和联系方便大家理解。
建议interactive_timeout和wait_timeout参数值配置成一样的。
1.interactive_timeout和wait_timeout概念wait_timeout非交互式连接超时通过jdbc连接数据库是非交互式连接,最大闲置时间用于规定一个connection最大的空闲时间,默认是28800秒,超时MySQL会自动回收该connection。
interactive_timeout交互式连接超时通过mysql客户端连接数据库是交互式连接,最大闲置时间用于规定一个connection最大的空闲时间,默认是28800秒,超时MySQL会自动回收该connection。
2.修改配置参数的方式
1.修改配置文件my.ini
[mysqld]
wait_timeout = 20 interactive_timeout = 20
2.执行mysql命令
#修改global级别的配置
set global interactive_timeout = 10;
set global wait_timeout = 10;
#修改session级别的配置
set session interactive_timeout=20;
set session wait_timeout=20;
3.查看参数配置
mysql> show variables like '%timeout%';
+-----------------------------+----------+
| Variable_name | Value |
+-----------------------------+----------+
| connect_timeout | 10 |
| delayed_insert_timeout | 300 |
| have_statement_timeout | YES |
| innodb_flush_log_at_timeout | 1 |
| innodb_lock_wait_timeout | 50 |
| innodb_rollback_on_timeout | OFF |
| interactive_timeout | 28800 |
| lock_wait_timeout | 31536000 |
| net_read_timeout | 30 |
| net_write_timeout | 60 |
| rpl_stop_slave_timeout | 31536000 |
| slave_net_timeout | 60 |
| wait_timeout | 28800 |
+-----------------------------+----------+
13 rows in set (0.00 sec)
3.参数不同的继承关系1.interactive_timeout和wait_timeout配置最终生效都是作用在session交互的时候生效。
2.控制最大空闲时间的参数是wait_timeout在起作用。不管是非交互式还是交互式连接,都是wait_timeout起作用
3.交互式连接下的wait_timeout和interactive_timeout配置都会继承自全局的interactive_timeout参数。
1.wait_timeout决定连接超时时间的演示
因为我们是用mysql客户端连接,应该是交互式连接,连接超时起作用的应该是interactive_timeout参数,但是真是的这样吗。
确认设置连接空闲超时时间是WAIT_TIMEOUT
============= wait_timeout ================
mysql> set session WAIT_TIMEOUT=2;
Query OK, 0 rows affected (0.00 sec)
等待2秒再次查询,连接已经丢失,说明配置生效。
mysql> select 1;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 50
Current database: *** NONE ***
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
============= interactive_timeout ================
mysql> set session interactive_timeout=2;
Query OK, 0 rows affected (0.00 sec)
等待2秒再次查询,连接也没有丢失,说明配置未生效。
mysql> select 1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
2.interactive_timeout不同的继承演示
设置interactive_timeout的配置
mysql> set global interactive_timeout=10;
Query OK, 0 rows affected (0.00 sec)
mysql> select variable_name,variable_value from information_schema.global_variables where variable_name in ('interactive_timeout','wait_timeout');
+---------------------+----------------+
| variable_name | variable_value |
+---------------------+----------------+
| INTERACTIVE_TIMEOUT | 10 |
| WAIT_TIMEOUT | 28800 |
+---------------------+----------------+
2 rows in set, 1 warning (0.00 sec)
新开一个窗口(交互式连接)查看,wait_timeout 和 interactive_timeout 都继承自global的interactive_timeout
交互式连接下可以看到interactive_timeout和wait_timeout都继承自全局INTERACTIVE_TIMEOUT
mysql> select variable_name,variable_value from information_schema.session_variables where variable_name in ('interactive_timeout','wait_timeout');
+---------------------+----------------+
| variable_name | variable_value |
+---------------------+----------------+
| INTERACTIVE_TIMEOUT | 10 |
| WAIT_TIMEOUT | 10 |
+---------------------+----------------+
2 rows in set, 1 warning (0.00 sec)
使用JDBC查询(非交互式)查看,wait_timeout继承自全局wait_timeout,interactive_timeout继承自全局interactive_timeout
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/deeluma_01", "root", "root");
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("select variable_name,variable_value from information_schema.session_variables where variable_name in ('interactive_timeout','wait_timeout')");
while(resultSet.next()){
String variable_name = resultSet.getString("variable_name");
int variable_value = resultSet.getInt("variable_value");
System.out.println(variable_name+":"+variable_value);
}
//非交互式下查看,wait_timeout继承自全局wait_timeout,interactive_timeout继承自全局interactive_timeout//===============//INTERACTIVE_TIMEOUT:10
WAIT_TIMEOUT:28800