
MYSQL_OPT_READ_TIMEOUT 是 MySQL c api 客户端中用来设置读取超时时间的参数。在 MySQL 的官方文档中,该参数的描述是这样的:
MYSQL_OPT_READ_TIMEOUT (argument type: unsigned int *)The timeout in seconds for each attempt to read from the server. There are retries if necessary, so the total effective timeout value is three times the option value. You can set the value so that a lost connection can be detected earlier than the TCP/IPClose_Wait_Timeout value of 10 minutes.
也就是说在需要的时候,实际的超时时间会是设定值的 3 倍。但是实际测试后发现实际的超时时间和设置的超时时间一致。
而具体什么时候发生三倍超时,在文档中没有找到。所以对 MySQL 5.7.20 的源码进行了一些分析。
使用 GDB 调试代码找了实际与 mysql server 通信的代码,如下:
请点击输入图片描述
其中 vio_read() 函数中,使用 recv 和 poll 来读取报文和做读取超时。net_should_retry() 函数只有在发生 EINTR 时才会返回 true。从这段代码来看是符合测试结果的,并没有对读取进行三次重试。只有在读取 *** 作被系统中断打断时才会重试,但是这个重试并没有次数限制。
从上面代码的分析可以看出,代码的逻辑和文档的描述不符。于是在一顿搜索后,找到了一个 MySQL 的 BUG(Bug #31163)。该 BUG 报告了在 MySQL 5.0 中,MySQL c api 读取的实际超时时间是设置的三倍,与现有文档描述相符。于是对 MySQL 5.0.96 的代码又进行分析。
同样使用 GDB 找到了通信部分的代码。这次找到了重试三次的代码,如下:
请点击输入图片描述
这个版本的 MySQL api 的读写超时是直接使用的 setsockopt 设置的。第一次循环,在 A 点发生了第一次超时(虽然注释写的非阻塞,但是客户端的连接始终是阻塞模式的)。然后在 B 点将该 socket 设置为阻塞模式,C 点这里重置 retry 次数。由于设置了 alarm 第二次以后的循环会直接进入 D 点的这个分支,并且判断循环次数。作为客户端时net->retry_count 始终是 1,所以重试了两次,共计进行了 3 次 vioread 后从 E 点退出函数。
由上面的分析可知,MySQL 文档对于该参数的描述已经过时,现在的 MYSQL_OPT_READ_TIMEOUT 并不会出现三倍超时的问题。而 Bug #31163 中的处理结果也是将文档中该参数的描述更新为实际读取超时时间是设定时间的三倍。也许是 MySQL 的维护者们在后续版本更新时忘记更新文档吧。
数据库连接数突增是数据库连接资源没有及时释放。连接数据库超时是因为数据库连接资源释放的过早。
现象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
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)