mysql timeout知多少

本文深入探讨MySQL中的多种timeout参数,包括connect_timeout、interactive_timeout、wait_timeout等,并通过实验验证它们的作用场景,帮助读者理解并合理配置这些参数。

1.timeout变量知多少

打开mysql,用show variables like '%timeout%'命令一看,不看不知道,一看吓一跳,结果如下面所示,这么多timeout相关变量,一下就吓尿了。。原来对mysql的了解原来是如此的不够,好了,这么些timeout究竟各自是什么意思,花了一下午去学习,做了几个小实验,总算明白了一二,如有错误,请不吝赐教啊。

mysql> show variables like '%timeout%';
+-----------------------------+----------+
| Variable_name               | Value    |
+-----------------------------+----------+
| connect_timeout             | 10       |
| delayed_insert_timeout      | 300      |
| 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           | 3600     |
| wait_timeout                | 28800    |
+-----------------------------+----------+
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

2.分析

下面从timeout里面找些比较常用的出来逐个分析下。

2.1 connect_timeout

connect_timeout指的是连接过程中握手的超时时间,在5.0.52以后默认为10秒,之前版本默认是5秒。官方文档是这样说的:

connect_timeout: The number of seconds that the mysqld server waits for a connect packet before responding with Bad handshake. The default value is 10 seconds as of MySQL 5.0.52 and 5 seconds before that
 
  • 1

mysql的基本原理应该是有个监听线程循环接收请求,当有请求来时,创建线程(或者从线程池中取)来处理这个请求。由于mysql连接采用TCP协议,那么之前势必是需要进行TCP三次握手的。TCP三次握手成功之后,客户端会进入阻塞,等待服务端的消息。服务端这个时候会创建一个线程(或者从线程池中取一个线程)来处理请求,主要验证部分包括host和用户名密码验证。host验证我们比较熟悉,因为在用grant命令授权用户的时候是有指定host的。用户名密码认证则是服务端先生成一个随机数发送给客户端,客户端用该随机数和密码进行多次sha1加密后发送给服务端验证。如果通过,整个连接握手过程完成。(具体握手过程后续找到资料再分析)

由此可见,整个连接握手可能会有各种可能出错。所以这个connect_timeout值就是指这个超时时间了。可以简单测试下,运行下面的telnet命令会发现客户端会在10秒后超时返回。

telnet localhost 3306
 
  • 1

在超时之前mysql中该连接状态如下:

256 | unauthenticated user | localhost:60595 | NULL | Connect | NULL | Reading from net | NULL 
 
  • 1

2.2 interactive_timeout & wait_timeout

还是先看官方文档,从文档上来看wait_timeout和interactive_timeout都是指不活跃的连接超时时间,连接线程启动的时候wait_timeout会根据是交互模式还是非交互模式被设置为这两个值中的一个。如果我们运行mysql -uroot -p命令登陆到mysql,wait_timeout就会被设置为interactive_timeout的值。如果我们在wait_timeout时间内没有进行任何操作,那么再次操作的时候就会提示超时,这是mysql client会重新连接。

The number of seconds the server waits for activity on a noninteractive connection before closing it.

On thread startup, the session wait_timeout value is initialized from the global wait_timeout value or from the global interactive_timeout value, depending on the type of client (as defined by the CLIENT_INTERACTIVE connect option to mysql_real_connect()).
 
  • 1
  • 2
  • 3

测试如下:

mysql> set global interactive_timeout=3; ##设置交互超时为3秒
 
  • 1

重新进入mysql,这时候可以看到:

mysql> show variables like '%timeout%'; ##wait_timeout已经被设置为3秒
+-----------------------------+----------+
| Variable_name               | Value    |
+-----------------------------+----------+
| connect_timeout             | 10       |
| delayed_insert_timeout      | 300      |
| innodb_flush_log_at_timeout | 1        |
| innodb_lock_wait_timeout    | 50       |
| innodb_rollback_on_timeout  | OFF      |
| interactive_timeout         | 3        |
| lock_wait_timeout           | 31536000 |
| net_read_timeout            | 30       |
| net_write_timeout           | 3        |
| rpl_stop_slave_timeout      | 31536000 |
| slave_net_timeout           | 3600     |
| wait_timeout                | 3        |
+-----------------------------+----------+
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

可以看到wait_timeout被设置为了interactive_timeout的值,这样,我们3秒后再执行其他命令,会提示如下:

mysql> show variables like '%timeout%';
ERROR 2006 (HY000): MySQL server has gone away  ##超时重连
No connection. Trying to reconnect...
Connection id:    50
Current database: *** NONE ***

+-----------------------------+----------+
| Variable_name               | Value    |
+-----------------------------+----------+
| connect_timeout             | 10       |
| delayed_insert_timeout      | 300      |
| innodb_flush_log_at_timeout | 1        |
| innodb_lock_wait_timeout    | 50       |
| innodb_rollback_on_timeout  | OFF      |
| interactive_timeout         | 3        |
| lock_wait_timeout           | 31536000 |
| net_read_timeout            | 30       |
| net_write_timeout           | 3        |
| rpl_stop_slave_timeout      | 31536000 |
| slave_net_timeout           | 3600     |
| wait_timeout                | 3        |
+-----------------------------+----------+
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

2.3 innodb_lock_wait_timeout & innodb_rollback_on_timeout

还是先祭出官方文档,从文档中看,这个值是针对innodb引擎的,是innodb中行锁的等待超时时间,默认为50秒。如果超时,则当前语句会回滚。如果设置了innodb_rollback_on_timeout,则会回滚整个事务,否则,只回滚事务等待行锁的这个语句。

The length of time in seconds an InnoDB transaction waits for a row lock before giving up. The default value is 50 seconds. A transaction that tries to access a row that is locked by another InnoDB transaction waits at most this many seconds for write access to the row before issuing the following error:

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

 
  • 1
  • 2
  • 3
  • 4

同样来测试下(先创建一个innodb引擎的表test,只有一列,列名为a):

mysql> CREATE TABLE `test` ( `a` int primary key) engine=innodb;

 
  • 1
  • 2

首先插入三条测试数据

mysql> select * from test;
+---+
| a |
+---+
| 1 |
| 2 |
| 3 |

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

当前innodb_rollback_on_timeout=OFF,设置innodb_lock_wait_timeout=1,我们开启两个事务

##事务1 加行锁
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test where a=2 for update;
+---+
| a |
+---+
| 2 |
+---+
1 row in set (0.01 sec)
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
##事务2,请求行锁
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from test where a=1;
Query OK, 1 row affected (0.00 sec)

mysql> delete from test where a=2; ##请求行锁超时
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> select * from test;
+---+
| a |
+---+
| 2 |
| 3 |
+---+
2 rows in set (0.00 sec)

mysql> begin; ##这里我们直接开启另外的事务,则原来的事务只会回滚第二条语句,最终结果就是test表中只剩下2和3.如果这里我们显示的rollback,则会回滚整个事务,保持1,2,3不变。

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

那么如果innodb_rollback_on_timeout=ON,同样事务2会超时,但是这个时候如果我们begin开启新的事务,那么会回滚请求锁超时的整个事务,而不是像前面那样只回滚了超时的那条语句。

2.4 lock_wait_timeout

文档中描述如下,简单说来lock_wait_timeout是元数据锁等待超时,任意锁元数据的语句都会用到这个超时参数,默认为一年。元数据锁可以参加mysql metadata lock,为了保证事务可串行化,不管是myisam还是innodb引擎的表,只要是开始一个事务,就会获取操作表的元数据锁,这时候如果另一个事务要对表的元数据进行修改,则会阻塞直到超时。

This variable specifies the timeout in seconds for attempts to acquire metadata locks. The permissible values range from 1 to 31536000 (1 year). The default is 31536000.

This timeout applies to all statements that use metadata locks. These include DML and DDL operations on tables, views, stored procedures, and stored functions, as well as LOCK TABLES, FLUSH TABLES WITH READ LOCK, and HANDLER statements
 
  • 1
  • 2
  • 3

测试例子: 
我们用一个myisam引擎的表myisam_test来测试。其中有一条记录(1,1),现在我们先开启一个session,然后执行一个select语句。另外打开一个session,然后执行表的元数据操作,如删除表,会发现操作阻塞直到lock_wait_timeout秒后提示超时。

##第一个session,获取metadata lock
mysql> show create table myisam_test;
-----------------------------------------------------------+
| Table       | Create Table                                                                                                                                |
+-----------------------------------------------------------
| myisam_test | CREATE TABLE `myisam_test` (
  `i` int(11) NOT NULL,
  `j` int(11) DEFAULT NULL,
  PRIMARY KEY (`i`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from myisam_test;
+---+------+
| i | j    |
+---+------+
| 2 |    1 |
+---+------+
1 row in set (0.00 sec)

##另一个session,删除表提示超时
mysql> drop table myisam_test;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

其中更改表结构的元数据操作指令有如下这些:

DROP TABLE t;
ALTER TABLE t ...;
DROP TABLE nt;
ALTER TABLE nt ...;
LOCK TABLE t ... WRITE;
 
  • 1
  • 2
  • 3
  • 4
  • 5

当然,多说一句,对于myisam表的加锁以及并发插入等,这篇博客myisam表锁非常详细,有兴趣的可以看看。

2.5 net_read_timeout & net_write_timeout

文档中描述如下,就是说这两个参数在网络条件不好的情况下起作用。比如我在客户端用load data infile的方式导入很大的一个文件到数据库中,然后中途用iptables禁用掉mysql的3306端口,这个时候服务器端该连接状态是reading from net,在等待net_read_timeout后关闭该连接。同理,在程序里面查询一个很大的表时,在查询过程中同样禁用掉端口,制造网络不通的情况,这样该连接状态是writing to net,然后在net_write_timeout后关闭该连接。slave_net_timeout类似。

The number of seconds to wait for more data from a connection before aborting the read. When the server is reading from the client, net_read_timeout is the timeout value controlling when to abort. When the server is writing to the client, net_write_timeout is the timeout value controlling when to abort
 
  • 1

测试: 
我创建一个120M的数据文件data.txt。然后登陆到mysql。

mysql -uroot -h 127.0.0.1 -P 3306 --local-infile=1
 
  • 1

导入过程设置iptables禁用3306端口。

iptables -A INPUT -p tcp --dport 3306 -j DROP
iptables -A OUTPUT -p tcp --sport 3306 -j DROP
 
  • 1
  • 2

可以看到连接状态为reading from net,然后经过net_read_timeout秒后关闭。

3.总结

经过几个实验可以发现,connect_timeout在握手认证阶段(authenticate)起作用,interactive_timeout 和wait_timeout在连接空闲阶段(sleep)起作用,而net_read_timeout和net_write_timeout则是在连接繁忙阶段(query)或者网络出现问题时起作用。

4.参考资料

<think> 我们正在讨论的是数据库连接池中的 `validation-query-timeout` 参数。根据用户提供的引用和之前的讨论,我们可以知道: 引用[2]提到MySQL服务器的`wait_timeout`默认为8小时,即连接空闲超过这个时间会被断开。引用[3]提到在Spring Boot中配置`autoReconnect=true`并不能完全解决连接断开的问题,因此需要其他配置。 `validation-query-timeout` 是连接池中用于设置验证查询(`validation-query`)执行时的超时时间。它的含义是:当连接池执行验证查询以检查连接是否有效时,如果超过这个时间还没有得到结果,就认为该连接已经失效。 作用: 1. 防止因为网络问题或数据库响应缓慢导致验证查询长时间阻塞,影响连接池的性能。 2. 确保连接验证操作不会无限期等待,从而快速淘汰无效连接。 使用方法(以Druid连接池为例): 在配置文件中(如`application.yml`)可以这样设置: ```yaml spring: datasource: druid: validation-query: SELECT 1 validation-query-timeout: 1 # 单位:秒 ``` 注意:不同的连接池可能有不同的配置方式,但参数含义相似。 为什么需要这个参数? 如果没有设置超时,当数据库服务器由于负载过高或网络问题导致响应变慢时,验证查询可能会长时间挂起,进而导致连接池中的所有线程都被阻塞,影响整个应用。 与`wait_timeout`的关系: 数据库的`wait_timeout`参数决定了连接空闲多久后被断开。而连接池的`validation-query-timeout`是为了确保在验证连接时不会等待过长时间。两者配合,可以更有效地管理连接。 最佳实践: 通常,这个值设置得比较小,比如1秒或2秒。因为验证查询(如`SELECT 1`)应该是非常快速的,如果超过这个时间,就可以认为连接有问题。 注意:在配置时,要确保这个值小于数据库的`wait_timeout`,否则在连接被数据库断开之前,验证查询可能已经超时了,这样会导致连接池频繁回收和创建连接,增加开销。 根据引用[2],MySQL的`wait_timeout`默认是8小时,所以我们可以将`validation-query-timeout`设置为1秒或2秒,这样既不会因为等待验证而阻塞太久,又能在连接失效时及时清除。 另外,引用[1]和引用[3]提到,有时候仅仅设置`autoReconnect=true`是不够的,还需要配合连接池的验证机制(包括`validation-query`和`validation-query-timeout`)来确保连接的有效性。 因此,我们可以这样总结: ### `validation-query-timeout` 详解 **含义** 用于设置连接池执行验证查询(`validation-query`)时的超时时间(单位通常为秒)。若在指定时间内未得到数据库响应,则判定该连接失效。 **作用** 1. 快速识别失效连接:避免因网络延迟或数据库响应缓慢导致连接验证阻塞 2. 保护系统稳定性:防止无效连接占用资源 3. 精准控制超时:与数据库的`wait_timeout`配合,实现双重保护机制 **配置示例(Spring Boot + Druid)** ```yaml spring: datasource: druid: # 基础连接配置 url: jdbc:mysql://localhost:3306/db?autoReconnect=true username: root password: 123456 # 连接验证配置 validation-query: SELECT 1 # 验证语句 validation-query-timeout: 1 # 超时1秒(关键配置) test-while-idle: true # 启用空闲检测 time-between-eviction-runs-millis: 30000 # 检测间隔 ``` **参数关系图解** ```mermaid graph TD A[数据库 wait_timeout] -->|断开空闲连接| B(连接失效) C[validation-query-timeout] -->|快速响应超时| D(标记无效连接) B --> E[连接池回收连接] D --> E ``` **使用建议** 1. **超时阈值**:通常设为 **1~3秒**(需小于数据库`wait_timeout`) 2. **组合配置**:必须与`validation-query`同时生效 3. **场景适配**: - 生产环境:建议启用(防止网络抖动导致连接池阻塞) - 测试环境:可关闭以简化配置 > ⚠️ 注意:部分连接池(如HikariCP)使用`connection-timeout`或`validation-timeout`作为等效参数,需根据实际连接池类型调整[^2][^3]。 最后,我们生成相关问题: §§相关问题§§ 1. `validation-query-timeout` 和数据库的 `wait_timeout` 之间有什么关系? 2. 如何为 HikariCP 连接池配置验证查询的超时时间? 3. 如果 `validation-query-timeout` 设置得比数据库的 `wait_timeout` 大会发生什么? 4. 除了超时设置,还有哪些方法可以防止数据库连接失效? 引用说明: [^1]: 关于Bitronix Transaction Manager的优雅关闭间隔配置 [^2]: MySQL服务器默认的wait_timeout设置 [^3]: Spring Boot连接池处理wait_timeout超时的配置经验 </think> ### `validation-query-timeout` 详解 #### **1. 核心含义** `validation-query-timeout` 是数据库连接池的关键参数,用于**限制连接有效性验证操作的超时时间**。当连接池执行 `validation-query`(如 `SELECT 1`)检查连接是否存活时,若在该时间内未得到数据库响应,则判定连接失效。 > 作用类比:相当于给连接健康检查设置的"心跳检测超时阈值"。 #### **2. 解决的问题** 结合用户引用中提到的场景: - MySQL 默认 `wait_timeout=28800秒`(8小时),空闲连接超时会被断开[^2] - 应用程序可能因连接失效报错(即使配置 `autoReconnect=true` 仍可能失败[^3]) - `validation-query-timeout` 确保连接池能**快速识别并替换失效连接**,避免以下错误: ```java Communications link failure // 网络中断或数据库重启导致 Connection reset by peer // 防火墙会话超时导致 ``` #### **3. 配置方法(Spring Boot + Druid 示例)** ```yaml spring: datasource: druid: validation-query: SELECT 1 # 验证语句 validation-query-timeout: 1 # 超时时间(秒) test-while-idle: true # 启用空闲检测 time-between-eviction-runs-millis: 30000 # 检测间隔 ``` #### **4. 参数关系图解** ```mermaid graph TD A[数据库连接] --> B{是否空闲超时?} B -- 是 --> C[执行 validation-query] C --> D{在 validation-query-timeout 内响应?} D -- 是 --> E[标记连接有效] D -- 否 --> F[销毁连接并创建新连接] ``` #### **5. 最佳实践建议** 1. **超时阈值设置** - 推荐值:**1~3秒**(需远小于数据库的 `wait_timeout`) - 计算公式: $$t_{timeout} < \frac{1}{10} \times t_{wait\_timeout}$$ 例如 MySQL 默认 8 小时,则 $t_{timeout} < 2880秒$,实际取 1-3 秒即可 2. **组合配置策略** ```yaml # 完整解决方案(防 wait_timeout 问题) validation-query: SELECT 1 validation-query-timeout: 1 test-while-idle: true min-evictable-idle-time-millis: 1800000 # 30分钟 < wait_timeout ``` 3. **不同连接池的等效参数** | 连接池 | 等效参数 | 单位 | |--------------|--------------------------|------| | HikariCP | `connection-timeout` | 毫秒 | | Tomcat JDBC | `validation-interval` | 毫秒 | | DBCP2 | `validation-query-timeout` | 秒 | > 💡 **生产经验**:超时值过小可能导致健康连接误判,过大则延缓故障响应,建议通过**模拟网络延迟测试**调整[^3]。 #### **6. 典型错误场景分析** 若未配置此参数,可能导致: 1. 当数据库响应缓慢时,验证操作阻塞线程池 2. 连接回收延迟,引发雪崩效应 3. 报错日志示例: ``` ERROR - Connection validation failed org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to validate connection within timeout ``` --- ### **相关问题** 1. `validation-query-timeout` 和数据库的 `wait_timeout` 有什么关系? 2. 如何验证 `validation-query-timeout` 配置是否生效? 3. 高并发场景下如何优化连接验证的超时设置? 4. 不同数据库(如 Oracle/PostgreSQL)是否需要不同的超时策略? [^1]: Spring Boot 事务优雅关闭配置 [^2]: MySQL 服务器默认 wait_timeout 参数说明 [^3]: Spring Boot 连接池超时问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值