对于多人开发的单体项目来说,虽然我们同时在用的连接不会超过10个,理论上100 绰绰有余,但是除了我们正在使用的连接以外,还有很大一部分 Sleep 的连接,这个才是真正的罪魁祸首。
分析到了问题的根源,我们就需要对症下药,依次解决:
修改MySQL最大连接数量
首先查看当前 Mysql 最大连接数量是多少:
show variableslike'%max_connections%'
这里我已经修改过了,所以是 1000,没有改过的童鞋应该还是 100,
然后查看从这次 mysql 服务启动到现在,同一时刻并行连接数的最大值:
show statuslike'Max_used_connections'
对于 MySQL 的最大连接数设置,在首次配置的时候设置一个较大的数值,以后在使用的过程中,周期的查询 Max_used_connections 然后根据他的值和服务器的性能确定一个最适合当前项目的最大连接数
最大连接数的修改有两种方式
使用 sql 语句(立即生效,但服务器重启后失效):
setglobalmax_connections = 1000
1修改 /etc/my.cnf.添加 max_connections = 1000 永久有效。重启后生效
但更改最大连接数只能从表面上解决问题,随着我们开发人员的增多,Sleep 连接也会更多,到时候万一又达到了 1000 的上限,难道我们又得改成 10000 吗?这显然是非常不可取的。所以我们不仅要治标,还要治本。杀掉多余的 Sleep 连接就是治本
杀掉Sleep连接
我们可以通过 show_processlist 命令来查看当前的所有连接状态
可以发现, Sleep 的连接占了绝大多数。
MySQL 数据库有一个属性 wait_timeout 就是 sleep 连接最大存活时间,默认是 28800 s,换算成小时就是 8 小时,我的天呐!这也太长了!严重影响性能。相当于今天上班以来所有建立过而未关闭的连接都不会被清理。
执行命令:
showglobalvariableslike'%wait_timeout'
我们将他修改成一个合适的值,这里我改成了 250s。当然也可以在配置文件中修改,添加 wait_timeout = 250。这个值可以根据项目的需要进行修改,以 s 为单位。我在这里结合 navicat 的超时请求机制配置了 240s。
执行命令:
setglobalwait_timeout=250
数据库连接数突增是数据库连接资源没有及时释放。连接数据库超时是因为数据库连接资源释放的过早。
现象1:每次上线项目DB的连接数会突增。
原因:是项目关闭的时候没有释放连接资源导致。
DB的connection资源没有正常释放,导致项目启动的时候再次创建数据库连接资源,就出现了连接数突增的现象。一段时间后mysql根据wait_time的配置,自动回收conncetion,所以连接数又回落回来。
如果是是DB的connection资源没有正常释放,最可能的是在项目关闭的时候没有释放掉DB的连接资源。
经过在查看线上jekins的上线脚本后,发现线上停止项目使用的kill进程的方式来停止项目。那么就证明假设都成立了。接下来解决问题环节(程序员们喜闻乐见的百度和谷歌环节了)。
解决方案
1.主动释放
项目关闭使用正确的stop命令,保证项目能正确的释放掉各种资源。
执行命令:xxxx_tomcat.stop
2.被动释放
现象2:连接数据库超时。
com.mysql.jdbc.CommunicationsException: The last packet successfully received from the server was58129 seconds ago.The last packet sent successfully to the server was58129seconds 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 valuesforclient timeouts, or using the Connector/J connection property'autoReconnect=true'to avoidthisproblem. mysql
问题原因 :连接池里的connection资源mysql主动提前释放导致。
原因是在datasource连接池中配置的最大空闲时间到达之前(比如maxIdleTime,不通数据源配置名不一样),已经到达mysql的wait_timeout(最大空闲时间),是mysql主动把connection资源回收。但是项目中的连接池还持有connection,所以当项目中使用connection的时候会报CommunicationsException错误。
解决方案
1.修改mysql的wait_time,interactive_timeout把值调大(不建议如果太大,可能导致连接数较多,引起性能下降)
2.配置JDBC的重连机制autoReconnect(不建议,只有4.x版本,起作用)
jdbc:mysql://localhost:3306/test?user=root&password=&autoReconnect=true
3.减少连接池内的存活时间+JDBC探活(建议,搭配使用效果好)
最大闲置资源时间的配置
两个现象的解决方案都指向了同一个配置就是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概念
mysql的连接超时时间配置
wait_timeout非交互式连接超时通过jdbc连接数据库是非交互式连接,最大闲置时间用于规定一个connection最大的空闲时间,默认是28800秒,超时MySQL会自动回收该connection。
interactive_timeout交互式连接超时通过mysql客户端连接数据库是交互式连接,最大闲置时间用于规定一个connection最大的空闲时间,默认是28800秒,超时MySQL会自动回收该connection。
2.修改配置参数的方式
1.修改配置文件my.ini
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")intvariable_value = resultSet.getInt("variable_value")System.out.println(variable_name+":"+variable_value)}//非交互式下查看,wait_timeout继承自全局wait_timeout,interactive_timeout继承自全局interactive_timeout//===============//INTERACTIVE_TIMEOUT:10WAIT_TIMEOUT:28800
释放连接只能是让一些连接的进程断开连接。查询哪个user的连接数最多,先跟他们的用户说,不能连接这么多的进程,让他们释放一些,如果释放了,系统正常了,那么就限制每个用户连接数,不让他们连接这么多。
如果不释放,你就在 *** 作系统层面把他们那些进程kill掉,有人来找就让他们对系统夯住负责,然后限制用户的连接数。
不过这么 *** 作的风险还是不小的,自己掂量。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)