MySQL - 各种超时时间 - 学习与探究

Posted 穿素白衫的中少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL - 各种超时时间 - 学习与探究相关的知识,希望对你有一定的参考价值。

1.应用场景

主要用于学习与探究mysql各种超时时间,应用在合适的场景下.

2.学习/操作

1.文档阅读

https://wen.geekr.dev/

2.整理输出

2.1 是什么

MySQL中有多个超时时间,以下是其中的几个:

  1. connect_timeout: 连接超时时间。它指的是连接 MySQL 服务器的客户端在规定时间内必须完成建立连接的动作,单位为秒。

  2. wait_timeout: 查询等待超时时间。它指的是当 MySQL 服务器在一定时间内没有接收到客户端任何请求时,就会主动关闭与客户端的连接,单位为秒。

  3. interactive_timeout: 交互式超时时间。它与 wait_timeout 的作用类似,不同点在于它只针对交互式工具(如 MySQL 命令行终端)的使用超时时间,单位为秒。

  4. net_read_timeout 和 net_write_timeout: 网络读写超时时间。这两个参数分别用于指定从 MySQL 服务器读取数据和向 MySQL 服务器写入数据的超时时间,单位为秒。如果在规定时间内没有完成读/写操作,则会关闭连接。

  5. lock_wait_timeout: 锁等待超时时间。该参数用于控制当某个 MySQL 事务在等待其它事务释放被锁定的资源时,最大等待的时间。

以上是 MySQL 中的几个超时时间,设置超时时间的主要目的是防止 MySQL 服务器因为客户端的不良行为(如长时间不使用建立连接)而出现性能问题。

2.2 为什么需要「应用场景」

MySQL之类的数据库设置各种超时时间,

主要是为了控制数据库的连接、查询和执行的时间,从而避免数据库资源被无限制地占用,避免出现类似死锁、卡死等异常情况

这些超时时间一般包括连接超时、查询超时、执行超时等,通过合理设置这些超时时间,可以提高数据库的稳定性和可靠性,也能够优化数据库的性能,提高数据库的响应速度。

2.3 什么时候出现「历史发展」

数据库连接超时、查询超时、执行超时等时间的设置在数据库的早期就已经出现了。

随着数据库的应用范围不断扩大,并且处理的数据量也越来越大,这些超时设置变得越来越重要。尤其是在高负载环境下,不合理的超时设置会导致数据库系统出现性能瓶颈,甚至崩溃。因此,对于数据库系统来说,合理设置超时时间是保证其稳定性、可靠性和高效性的关键。

2.4 怎么实践

1. 如何查看上面的超时时间

在 MySQL 中,您可以使用 SHOW VARIABLES 命令来查看当前 MySQL 实例中各种系统变量的值,也包括一些超时时间的相关配置。

例如,要查看 MySQL 实例中的 wait_timeout 和 interactive_timeout 参数的值,您可以使用下面的命令:

SHOW VARIABLES LIKE 'wait_timeout';
SHOW VARIABLES LIKE 'interactive_timeout';

这将返回类似于以下结果:

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout | 28800 |
+---------------+-------+

+---------------------+-------+
| Variable_name | Value |
+---------------------+-------+
| interactive_timeout | 28800 |
+---------------------+-------+

类似地,您也可以使用命令查看其他超时时间参数的值。如果您不确定参数的名称,可以在命令中使用通配符 %。

SHOW VARIABLES LIKE '%timeout%';

最后,值得注意的是,SHOW VARIABLES 命令只会列出当前会话使用的参数值。如果您希望查看 MySQL 服务器上的全局参数值,您可以使用通用查询日志或者在 MySQL 配置文件中查看参数配置。

延伸问题

当前会话使用的参数值与服务器上的全局参数值有什么区别?

在MySQL中,有两种类型的系统变量:会话级变量和全局级变量。

会话级变量是会话(连接)特定的变量。也就是说,每个MySQL 连接都可以拥有自己的参数配置。当连接MySQL实例时,MySQL会话会继承全局变量的默认值,但如果连接的时候设置了某个参数的值,该值将覆盖全局默认值,直到连接关闭。

全局级变量是指对于整个MySQL实例(即服务器)都是相同的设置。这些变量是指定MySQL服务器的默认行为,并在会话连接以前进行配置,对于启动后产生的所有连接均有效。

当使用 SHOW VARIABLES 命令来查询系统变量和参数,查询结果中的值要么是当前会话(连接)使用的参数值,要么是全局参数的值。

如果当前MySQL连接没有指定一个参数值,则该参数值将从全局级别获取。如果当前MySQL连接指定了一个参数值或更改了基本配置,那么该值将覆盖全局值,同时只会影响当前会话。这就是MySQL会话级变量与全局级变量的主要区别。

举一反三:

还有哪些服务,软件,系统也提供了相同或类似的特性

像 MySQL 这样的服务、软件和系统在其配置中提供了许多不同类型的特性来调整其行为。

以下是一些示例:

  1. Apache HTTP Server:与MySQL类似,Apache HTTP Server支持许多不同类型的设置和配置,可以通过编辑配置文件来进行调整。例如,可以配置 KeepAliveTimeout 参数来指定与客户端建立的连接在空闲时间段后关闭的时间。

  2. nginx:Nginx也是一种广泛使用的Web服务器,支持各种设置和调整,可用于改善性能和安全。例如,可以使用 client_body_timeout 和 client_header_timeout 参数来控制对客户端请求超时后执行的操作。

  3. Linux 系统:许多Linux发行版和内核提供了许多可调整的系统参数。例如,可以设置 sysctl 参数来调整内核 TCP/IP 闲置超时时间。

  4. 网络设备:诸如防火墙、负载均衡器和路由器等网络设备也通常提供许多不同类型的设置和配置,用于调整其行为和性能。例如,可以设置 NAT 超时时间限制以管理出站连接的生命周期。

总之,许多不同的服务、软件和系统都提供了可调整的特性或参数,用于优化其性能、安全性或其他方面的行为。这些特性通常在其相应的文档中进行记录,并且可以通过编辑配置文件或管理界面进行调整。

2. 如何修改这些超时时间

方式一:通过会话连接进行设置【只是针对当前会话】

方式二:通过全局配置进行设置,即mysql服务器配置文件 【针对所有连接】

不过优先级:会话配置 > 全局配置

3. navicat连接mysql用到了哪些超时配置?

Navicat是一个跨平台的数据库管理工具,可以连接MySQL数据库,其中涉及几个超时配置,如下所示:

  1. 连接超时时间:它指连接MySQL服务的客户端在规定的时间内必须完成建立连接的动作,单位为秒。默认的 Navicat 连接超时时间为 30 秒,如果您需要更改它,可以在“连接参数”窗口的“高级”选项中进行设置。

  2. 查询等待超时时间:它指当MySQL服务器在一定时间内没有接收到客户端任何请求时,就会主动关闭与客户端的连接,单位为秒。Navicat的默认查询等待超时时间为0(没有超时限制),如果需要更改它,可以在“连接参数”窗口的“高级”选项中进行设置。

  3. 读取数据超时时间和写入数据超时时间:当从数据库读取或写入数据时,Navicat 还使用两个超时配置。这些超时时间默认为0(没有超时限制),但您可以在“链接属性”窗口中的“SSH”选项卡下设置这些配置。

需要注意的是,这些超时配置可以因MySQL数据库版本、网络环境和服务器负载而有所不同。因此,您可以根据实际情况来调整这些超时时间的值。

 不过这里并没有找到,tbd

过了一天,navicat提示丢失连接,是什么情况?如何解决?

如果Navicat在连接MySQL后不久就提示连接丢失,这可能是由于超时配置或网络问题引起的。下面是一些可能的解决方法:

  1. 检查超时配置:这可能是连接丢失的常见原因之一。Navicat使用连接、查询、读取和写入超时等参数来管理连接,如前面所提到的。可以尝试增加这些超时值或设置为“0”来禁用它们,确保连接不会在非常短的时间内关闭。

  2. 检查MySQL服务器配置:如果检查Navicat的超时配置没有问题,可以检查MySQL服务器的配置文件(如my.cnf)是否有超时限制。MySQL的默认wait_timeout和interactive_timeout设置为8小时,如果MySQL服务器更改为较短的时间,这也可能是导致Navicat失去连接的原因之一。在这种情况下,将服务器配置更改回默认值可能会有所帮助。

  3. 检查网络连接和负载:如果Navicat提示连接丢失,可能是由于网络问题或MySQL服务器的负载过高而造成的。检查网络连接是否不稳定、网络延迟是否过高以及MySQL服务器的负载情况等,并尝试重新连接。如果网络连接不稳定,可能需要进行更改或升级以提高质量。

  4. 升级Navicat:如果Navicat版本比较旧,可能存在某些已知问题,通过升级Navicat软件的版本,有可能解决该问题。在升级之前建议先备份Navicat的配置和数据。

总之,Navicat提示“连接丢失”的问题可能是由于超时配置、MySQL服务器配置、网络问题或软件问题引起的。需要根据具体情况来进行排查和解决。

3. wait_timeout 和 interactive_timeout 的区别 举例解释

wait_timeout 和 interactive_timeout 都是 MySQL 中的超时时间。

它们之间的区别在于:wait_timeout 只是指定当 MySQL 服务器在一定时限内没有收到任何客户端请求时关闭该连接,而 interactive_timeout 则指定了当 MySQL 处于空闲状态时关闭连接的时间。

举个例子来说明两者之间的区别。

比如有一个 MySQL 客户端正在通过 Navicat 连接到 MySQL 服务器处理任务。该客户端的连接到达 MySQL 服务器之后,开始执行一些查询和操作,期间不断向服务器发送请求。如果在特定时间(由 wait_timeout 参数设置)之后,客户端没有向 MySQL 服务器发送任何请求,MySQL 服务器会自动关闭该连接。这适用于非交互式会话,例如脚本或程序中的 MySQL 连接。

相比之下,interactive_timeout 更多用于交互式会话,例如通过 MySQL 的命令行界面或 Navicat 等工具连接 MySQL 服务器。这些工具通常会维持一个连接,在用户通过该连接执行输入的查询字符串或指令,完成查询、数据修改等任务。在用户输入查询字符串或指令后,如果达到 interactive_timeout 参数设置的时间,而 MySQL 没有收到任何用户请求,则 MySQL 会在空闲时间到期后关闭这个连接。

需要注意的是,默认情况下,MySQL 的 interactive_timeout 和 wait_timeout 参数的值是相同的,都是 28800 秒(8 小时),可以在 MySQL 的配置文件或 MySQL 客户端中进行设置和修改。

如果在进行 MySQL 相关的开发或管理时,需要经常使用 MySQL 命令行或 Navicat 等工具,那么需要对 interactive_timeout 参数进行适当的调整,以便避免在交互过程中突然丢失连接。

问题扩展

Navicat常规连接mysql使用的是wait_timeout 还是 interactive_timeout?

Navicat 使用的是 wait_timeout 而不是 interactive_timeout。

wait_timeout 是 MySQL 中控制当 MySQL 服务器在一定时间内没有收到任何客户端请求时关闭该连接的超时配置,单位为秒。默认情况下,wait_timeout 的值是 8 小时,或者在 MySQL 配置文件 my.cnf 中设置为其它的值。当 Navicat 连接 MySQL 服务器时,会根据 wait_timeout 参数的设置对连接进行超时检测,如果在规定时间内(默认 8 小时)Navicat 没有向 MySQL 服务器发送任何请求,那么 MySQL 服务器就会关闭与 Navicat 的连接并回收相关资源。

需要注意的是,Navicat 的超时限制不同于 Interactive_timeout 的超时限制。Interactive_timeout 通常用于控制交互式会话的超时时间,例如 MySQL 的命令行界面等。

Navicat 作为一款图形界面工具,更适合用 wait_timeout 来控制超时时间,因此使用的是 wait_timeout。

总之,无论是 wait_timeout 还是 interactive_timeout,都是 MySQL 中常用的控制超时的参数,其应用场景和作用略有不同。在使用 Navicat 连接 MySQL 数据库的过程中,应该了解和适当调整这些超时参数值以避免连接过早失效。

Navicat常规连接MySQL使用的是wait_timeout,而不是interactive_timeout,因为MySQL对于连接和交互的操作,分别设定了这两个超时参数。

wait_timeout指定了MySQL在等待客户端发送数据的时间。如果客户端在这段时间内没有发送数据,MySQL会自动关闭连接。wait_timeout的默认时间是8小时(28800秒)。

interactive_timeout指定了MySQL与客户端之间的交互超时时间。如果客户端在这段时间内不发送新的数据,MySQL则终止连接。这个超时时间同样是默认设置为8小时(28800秒)。

Navicat在连接MySQL服务器时,会对连接进行一系列的操作和交互,这时会受到wait_timeout的影响,如果超过wait_timeout的时间,MySQL就会关闭连接。而在连接之后的交互过程中,受到interactive_timeout的限制,如果超过这个时间,MySQL同样也会关闭连接。

Navicat的命令列界面使用的是wait_timeout 还是 interactive_timeout?

Navicat 并不提供自己的命令行界面,因此,在使用 Navicat 的命令行界面(如 Navicat Premium Essentials 中的 Query 菜单)时,实际上使用的是 MySQL 的命令行界面(mysql)。

因此,任何适用于 MySQL 的超时参数配置都会应用于 Navicat 的命令行界面。

默认情况下,MySQL 的 interactive_timeout 和 wait_timeout 参数的值是相同的,即 8 小时(或在 my.cnf 文件中设置的其他值)。这意味着,如果您使用 Navicat 的命令行接口,则默认情况下使用的是 wait_timeout 而不是 interactive_timeout。这是指当连接到 MySQL 数据库的客户端在一段时间内没有使用连接时,MySQL 服务器将自动关闭与该客户端的连接。

需要注意的是,在 MySQL 命令行界面中,您可以通过输入以下命令修改 interactive_timeout 的值,以控制 MySQL 命令行界面的交互可能的超时时间:

SET GLOBAL interactive_timeout = 3600; -- 将 interactive_timeout 值设置为 1 小时(3600 秒)

当然,此处所做的更改仅影响当前的 MySQL 会话,不会影响任何其他会话或全局 MySQL 配置。

总而言之,Navicat 的命

MySQL自带的命令行工具mysql,使用的是wait_timeout 还是 interactive_timeout?

MySQL自带的命令行工具mysql,使用的是interactive_timeout而不是wait_timeout,两者的含义略有不同:

wait_timeout指定了一个连接在空闲状态下可以保持多长时间,若超过这个时间,连接就会自动断开。这个时间比较短,通常是几秒钟到几分钟。wait_timeout的默认值为28800秒(8小时)。

interactive_timeout则是指定一个连接在空闲状态下可以保持的时间(单位为秒),等于或小于wait_timeout。interactive_timeout的默认值为28800秒(8小时)。如果客户端工具一直保持与MySQL的连接,并且空闲时间不超过interactive_timeout,那么与MySQL的连接就一直保持,不会被断开。

因此,对于mysql命令行工具,如果一直与MySQL保持连接,并发送交互式的命令,则会使用interactive_timeout。如果连接空闲,则可能会在wait_timeout时间内关闭连接。

Navicat的命令列界面console使用的是wait_timeout 还是 interactive_timeout?

Navicat的命令行界面console也使用的是 interactive_timeout,而不是 wait_timeout。这个timeout与MySQL服务器的interactive_timeout的设定参数相关。当客户端不再向服务器发送指令时的等待时间超过interactive_timeout时,服务器会自动关闭连接,因此这个timeout也称为连接超时。interact_timeout默认的时间是8小时(28800秒),但是也可以根据需要进行修改。在Navicat的console界面使用时,同样会受到interactive_timeout的限制,连接会在idle状态下被超时关闭,避免数据库连接资源被长时间占用。

 

如果MySQL 的配置文件和MySQL 客户端中都设置超时时间,哪个配置生效?

如果MySQL配置文件和MySQL客户端中都设置了超时时间,那么以MySQL客户端中配置的超时时间为准。这是因为MySQL客户端中配置的超时时间会优先覆盖MySQL配置文件中的设置。【这也是会话级变量优先与全局级变量,不然就没意义了

也就是说,在MySQL客户端中进行的超时时间配置是局部配置,只对当前的客户端生效,而在MySQL配置文件中进行的超时时间配置是全局配置,适用于所有的客户端。如果二者设置不一致,MySQL客户端会优先使用自己的超时时间配置。因此,在实际中应该根据具体情况进行超时时间的设置,避免造成不必要地资源浪费或者连接异常。

4. mysql中wait_timeout和interactive_timeout等超时是如何检测的?

MySQL中的wait_timeout和interactive_timeout是通过MySQL服务器来检测的具体实现使用TCP keep-alive机制。当MySQL服务器连接的客户端小于等于wait_timeout的值时,服务器会定期发送一个特殊的TCP keep-alive消息给客户端,如果客户端没有响应,则认为该客户端已经断开连接,将该连接关闭掉。通过定期发送TCP keep-alive消息,可以避免因为某些原因客户端没有正式关闭连接而一直占用MySQL服务器资源的情况。

MySQL的 interactive_timeout 的检测方式和wait_timeout类似,只不过检测的对象是连接上发生的交互,如果一段时间内没有交互,则会自动关闭连接。

需要注意的是,这两个超时时间的时间参数是在MySQL服务器上设置的,超时的触发是在MySQL服务器端进行的,而不是在客户端。在客户端,可以通过连接状态(状态码)来得知连接是否已经被服务器端关闭。

后续补充

...

3.问题/补充

TBD

后续补充

...

MySQL 各种超时参数的含义

MySQL 各种超时参数的含义

  • 今日在查看锁超时的设置时,看到show variables like ‘%timeout%‘;语句输出结果中的十几种超时参数时突然想整理一下,不知道大家有没有想过,这么多的timeout参数,到底有什么区别,都是做什么用的呢?
MySQL [(none)]> show variables like ‘%timeout%‘;
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |
+------------------------------+----------+
13 rows in set (0.00 sec)
  • PS:文档说明
  • 根据这些参数的global和session级别分别进行阐述
  • 基于MySQL 5.6.30编写
  • 加载了半同步复制插件,所以才能看到半同步相关的参数
  • 验证演示过程可能会打开两个MySQL会话进行验证,也可能只打开一个MySQL会话进行验证
  • 只针对大家平时容易高混淆的或者说不好理解的超时参数做步骤演示,容易理解的超时参数只做文字描述,不做步骤演示
  • 大部分参数基于MySQL命令行客户端做的演示,但wait_timeout和interactive_timeout这两个比较特殊,为了对比不同客户端的差异,还使用了python演示

1、连接、网络类超时

  • 共有如下几个:
  • connect_timeout:默认为10S
  • wait_timeout:默认是8小时,即28800秒
  • interactive_timeout:默认是8小时,即28800秒
  • net_read_timeout:默认是30S
  • net_write_timeout:默认是60S

1.1. 针对网络类超时参数,先简单梳理一下在MySQL建立连接、发送数据包的整个过程中,每一个阶段都用到了哪些超时参数

a)、connect_timeout:在获取连接阶段(authenticate)起作用

  • 获取MySQL连接是多次握手的结果,除了用户名和密码的匹配校验外,还有IP->HOST->DNS->IP验证,任何一步都可能因为网络问题导致线程阻塞。为了防止线程浪费在不必要的校验等待上,超过connect_timeout的连接请求将会被拒绝。
  • 官方描述: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)

b)、interactive_timeout和wait_timeout:在连接空闲阶段(sleep)起作用

  • 即使没有网络问题,也不能允许客户端一直占用连接。对于保持sleep状态超过了wait_timeout(或interactive_timeout,取决于client_interactive标志)的客户端,MySQL会主动断开连接。
  • 官方描述:
  • wait_timeout: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_timeoutvalue, depending on the type of client (as defined by the CLIENT_INTERACTIVE connect option to mysql_real_connect()).

  • interactive_timeout:The number of seconds the server waits for activity on an interactive connection before closing it. An interactive client is defined as a client that uses the CLIENT_INTERACTIVE option to mysql_real_connect()

c)、net_read_timeout和net_write_timeout:则是在连接繁忙阶段(query)起作用。

  • 即使连接没有处于sleep状态,即客户端忙于计算或者存储数据,MySQL也选择了有条件的等待。在数据包的分发过程中,客户端可能来不及响应(发送、接收、或者处理数据包太慢)。
  • 为了保证连接不被浪费在无尽的等待中,MySQL也会选择有条件(net_read_timeout和net_write_timeout)地主动断开连接。
  • 这个参数只对TCP/IP链接有效,只针对在Activity状态下的线程有效
  • 官方描述:
  • net_read_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
  • net_write_timeout:The number of seconds to wait for a block to be written to a connection before aborting the write. See also net_read_timeout.

d)、 handshake流程

  • 在TCP三次握手的基础之上,简历MySQL通讯协议的连接,这个连接建立过程受connect_timeout参数控制
    --------------------TCP established--------------------
    MySQL Server(10.10.20.96)------->Client(10.10.20.51)
    Client(10.10.20.51)------->MySQL Server(10.10.20.96)
    MySQL Server(10.10.20.96)------->Client(10.10.20.51)

--------------------established--------------------

  • 在MySQL通讯协议建立连接之后,此时客户端连接的超时受wait_timeout和interactive_timeout参数控制
    建立连接后无交互:MySQL server ---wait_timeout--- Client
    建立连接交互后:MySQL server ---interactive_timeout--- Client

  • 在如果客户端有数据包传输,那么这个数据包的传输超时由net_read_timeout和net_write_timeout参数控制
    -------------------client与server端有数据传输时-------------------
    client ----->MySQL Server(net_read_timeout)
    client <-----MySQL Server(net_write_timeout)

1.2. connect_timeout:该参数没有session级别,是一个global级别变量

## 使用mysql客户端打开一个会话,并设置全局 connect_timeout=5
MySQL [(none)]> set global connect_timeout=5;
Query OK, 0 rows affected (0.00 sec)

MySQL [(none)]> 

## 由于mysql客户端不是很好模拟连接阶段(authenticate)的超时,所以使用telnet来发包给mysql,因为telnet的包并不遵循mysql的通讯协议
[[email protected] ~]# time telnet 127.0.0.1 3306
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is ‘^]‘.
N
5.6.30-logwA{k)‘&)S9#A`?Z&O9pJ`mysql_native_passwordConnection closed by foreign host.

real    0m5.022s  #这里可以看到5S之后连接断开
user    0m0.000s
sys 0m0.010s

## 回到mysql客户端:修改全局 connect_timeout为10S
MySQL [(none)]> set global connect_timeout=10;
Query OK, 0 rows affected (0.00 sec)

MySQL [(none)]> 

## 使用telnet再试一次
[[email protected] ~]# time telnet 127.0.0.1 3306
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is ‘^]‘.
N
5.6.30-loggZoA3{6:SD}iu3;n:uafmysql_native_passwordConnection closed by foreign host.

real    0m10.012s
user    0m0.000s
sys 0m0.002s
  • 从上面的结果中可以看到,MySQL客户端与服务端的连接阶段(authenticate)的超时由参数connect_timeout控制。

1.3. interactive_tineout和wait_timeout参数

1.3.1. interactive_timeout:(MySQL命令行客户端)
1.3.1.1. session级别修改interactive_timeout
## 打开第一个会话,设置session级别的interactive_timeout=2
MySQL [(none)]> set session interactive_timeout=2;
Query OK, 0 rows affected (0.00 sec)

MySQL [(none)]> select sleep(3);show session variables like ‘%timeout%‘;show global variables like ‘%timeout%‘;
+----------+
| sleep(3) |
+----------+
|        0 |
+----------+
1 row in set (3.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 2        |  #session级别的interactive_timeout改变了
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |  #session级别的wait_timeout没有影响
+------------------------------+----------+
13 rows in set (0.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |  #global级别的interactive_timeout没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |  #global级别的wait_timeout没有影响
+------------------------------+----------+
13 rows in set (0.00 sec)

## 打开第二个会话,执行show语句
MySQL [(none)]> show session variables like ‘%timeout%‘;show global variables like ‘%timeout%‘;
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |  #session级别的interactive_timeout没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |  #session级别的wait_timeout没有影响
+------------------------------+----------+
13 rows in set (0.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |  #global级别的interactive_timeout没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |  #global级别的wait_timeout没有影响
+------------------------------+----------+
13 rows in set (0.00 sec)
  • 从上面的结果可以看到,设置session级别的interactive_timeout对wait_timeout的session和global级别都没有影响
1.3.1.2. global级别修改interactive_timeout
### 回到第一个会话中,设置global interactive_timeout=20
MySQL [(none)]> set global interactive_timeout=20;
Query OK, 0 rows affected (0.00 sec)

MySQL [(none)]> select sleep(3);show session variables like ‘%timeout%‘;show global variables like ‘%timeout%‘;
+----------+
| sleep(3) |
+----------+
|        0 |
+----------+
1 row in set (3.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 2        |  #session级别的interactive_timeout没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |  #session级别的wait_timeout没有影响
+------------------------------+----------+
13 rows in set (0.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 20       |  #global级别的interactive_timeout改变了
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |  #global级别的wait_timeout没有影响
+------------------------------+----------+
13 rows in set (0.00 sec)

# 第二个会话断开之后重连,再执行show语句
MySQL [(none)]> show session variables like ‘%timeout%‘;show global variables like ‘%timeout%‘;
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 20       |  #session级别的interactive_timeout改变了
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 20       |  #session级别的wait_timeout改变了
+------------------------------+----------+
13 rows in set (0.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 20       |  #global级别的interactive_timeout改变了
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |  #global级别的wait_timeout没有影响
+------------------------------+----------+
13 rows in set (0.00 sec)
  • 从上面的结果中可以看到:如果改变了global级别的interactive_timeout值,对当前连接不生效,对后续新连接的wait_timeout的session级别生效,global级别不生效,interactive_timeout的global级别和session级别都生效
1.3.2. wait_timeout:(MySQL命令行客户端)
1.3.2.1. session级别修改wait_timeout
  • 这里为了验证后续的值不产生混乱,先把interactive_timeout的值恢复为172800并重连连接(connect_timeout默认是10,此时已经是这个值了,不用再修改),然后再修改wait_timeout
MySQL [(none)]> set global interactive_timeout=172800;
Query OK, 0 rows affected (0.00 sec)

MySQL [(none)]> Ctrl-C -- exit!
Aborted
[[email protected] ~]# mysql -uqogir_env -p‘letsg0‘ -S /home/mysql/data/mysqldata1/sock/mysql.sock 
Welcome to the MariaDB monitor.  Commands end with ; or g.
Your MySQL connection id is 21
Server version: 5.6.30-log MySQL Community Server (GPL)

Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others.

Type ‘help;‘ or ‘h‘ for help. Type ‘c‘ to clear the current input statement.

MySQL [(none)]> show session variables like ‘%timeout%‘;show global variables like ‘%timeout%‘;
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |
+------------------------------+----------+
13 rows in set (0.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |
+------------------------------+----------+
13 rows in set (0.00 sec)
  • 现在,开始1.3.2.小节的验证

# 打开第一个会话,修改session级别wait_timeout=2
MySQL [(none)]> set session wait_timeout=2;
Query OK, 0 rows affected (0.00 sec)

MySQL [(none)]> select sleep(3);show session variables like ‘%timeout%‘;show global variables like ‘%timeout%‘;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    22
Current database: *** NONE ***  #从这里可以看到,当前连接被断开并重连了

+----------+
| sleep(3) |
+----------+
|        0 |
+----------+
1 row in set (3.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |  #重连之后的session级别参数, interactive_timeout 没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |  #重连之后的session级别参数,wait_timeout恢复了172800
+------------------------------+----------+
13 rows in set (0.01 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |  #重连之后的global级别参数, interactive_timeout 没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   | #重连之后的global级别参数,wait_timeout恢复了172800,即新的连接不受影响
+------------------------------+----------+
13 rows in set (0.00 sec)

# 打开第二个会话,第二个会话注意要重连
MySQL [(none)]> show session variables like ‘%timeout%‘;show global variables like ‘%timeout%‘;
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |  #session级别的interactive_timeout没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |  #session级别的wait_timeout没有影响
+------------------------------+----------+
13 rows in set (0.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |  #global级别的interactive_timeout没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   | #global级别的wait_timeout没有影响
+------------------------------+----------+
13 rows in set (0.00 sec)

# 对于超时断开的连接,错误日志中会报如下错误:
2016-11-07 19:08:24 3391 [Warning] Aborted connection 21 to db: ‘unconnected‘ user: ‘qogir_env‘ host: ‘localhost‘ (Got timeout reading communication packets)
  • 从上面的结果中可以看到:
  • session级别的wait_timeout变量在连接初始化时,继承global的interactive_timeout参数值
  • session级别的wait_timeout对当前交互连接生效(即当前连接的超时使用的是session wait_timeout,session interactive_timeout不生效)
  • 有一点要注意,如果是新的连接(即断开重连的或者新的连接),session级别的wait_timeout会使用global级别的interactive_timeout值覆盖,因为interactive_timeout值是对后续新连接生效(参考1.2.2小节验证过程)
1.3.2.2. global级别修改wait_timeout

# 打开第一个会话,修改global wait_timeout=2
MySQL [(none)]> set global wait_timeout=2;
Query OK, 0 rows affected (0.00 sec)

MySQL [(none)]> select sleep(3);show session variables like ‘%timeout%‘;show global variables like ‘%timeout%‘;
+----------+
| sleep(3) |
+----------+
|        0 |
+----------+
1 row in set (3.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |  #session级别的interactive_timeout没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |  #session级别的wait_timeout没有影响
+------------------------------+----------+
13 rows in set (0.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |  #global级别的interactive_timeout没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 2        |  #global级别的wait_timeout改变了
+------------------------------+----------+
13 rows in set (0.00 sec)

# 打开第二个会话,注意需要断开重连,再执行show语句
MySQL [(none)]> show session variables like ‘%timeout%‘;show global variables like ‘%timeout%‘;
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |  #session级别的interactive_timeout没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 172800   |  #session级别的wait_timeout没有影响,因为前面说过,这里新连接的session的wait_timeout会继承global interactive_timeout的值
+------------------------------+----------+
13 rows in set (0.00 sec)

+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| connect_timeout              | 10       |
| delayed_insert_timeout       | 300      |
| innodb_flush_log_at_timeout  | 1        |
| innodb_lock_wait_timeout     | 120      |
| innodb_rollback_on_timeout   | ON       |
| interactive_timeout          | 172800   |  #global级别的interactive_timeout没有影响
| lock_wait_timeout            | 31536000 |
| net_read_timeout             | 30       |
| net_write_timeout            | 60       |
| rpl_semi_sync_master_timeout | 10000    |
| rpl_stop_slave_timeout       | 31536000 |
| slave_net_timeout            | 10       |
| wait_timeout                 | 2        |  #global级别的wait_timeout改变了
+------------------------------+----------+
13 rows in set (0.00 sec)
  • 从上面的结果中可以看到:global级别的wait_timeout变量在初始化时,继承global的wait_timeout参数值,默认8小时
1.3.3. interactive_timeout和wait_timeout参数(python MySQL driver)
  • 本小节演示的python代码如下:

#cat test_timeout.py 
#!/bin/env python
# coding=utf8

import MySQLdb
import sys
import time

# 设置wait_timeout的值
wait_timeout=5

# 设置interactive_timeout的侄
interactive_timeout=10

# MySQL帐号
mysql_user=‘qbench‘

# MySQL密码
mysql_password=‘qbench‘

# MySQL ip地址
mysql_ip=‘10.10.30.68‘




rest_conn = MySQLdb.connect(user=mysql_user,passwd=mysql_password,host=mysql_ip)
rest_cur = rest_conn.cursor()
rest_cur.execute("show variables like ‘%timeout%‘;")
datas = rest_cur.fetchall()
datas = dict(datas)
    
rest_wait_timeout = datas[‘wait_timeout‘]
rest_interactive_timeout = datas[‘interactive_timeout‘]

rest_cur.close()
rest_conn.close()


def new_connect(info,timeout):
    new_conn = MySQLdb.connect(user=mysql_user,passwd=mysql_password,host=mysql_ip)
    new_cur = new_conn.cursor()
    print ‘%s 
%s‘ % (‘-‘ * 50,str(info))
    #sql = "select sleep(%s);" % int(timeout+1)
    #print "执行sleep sql语句:%s" % str(sql)
    new_cur.execute("show variables like ‘%timeout%‘;")
    new_datas = new_cur.fetchall()
    new_datas = dict(new_datas)
    
    print ‘wait_timeout=%s‘ % new_datas[‘wait_timeout‘]
    print ‘interactive_timeout=%s‘ % new_datas[‘interactive_timeout‘]

    print "sleep %s 秒之后再次执行sql---" % int(timeout)
    time.sleep(int(timeout))
    #new_cur.execute("%s" % str(sql))
    new_cur.execute("show variables like ‘%timeout%‘;")
    new_datas = new_cur.fetchall()
    new_datas = dict(new_datas)
    
    print ‘wait_timeout=%s‘ % new_datas[‘wait_timeout‘]
    print ‘interactive_timeout=%s‘ % new_datas[‘interactive_timeout‘]

    new_cur.close()
    new_conn.close()

def current_connect():
    curr_conn = MySQLdb.connect(user=mysql_user,passwd=mysql_password,host=mysql_ip)
    curr_cur = curr_conn.cursor()
    print "在第一个连接中修改global wait_timeout为:%s" % wait_timeout
    curr_cur.execute("set global wait_timeout=%s;" % wait_timeout)
    curr_cur.execute("show variables like ‘%timeout%‘;")
    curr_datas1 = curr_cur.fetchall()
    curr_datas1 = dict(curr_datas1)
    
    print "%s
第一个连接保持不断开的session级别的超时信息:" % (‘-‘ * 100) 
    print ‘wait_timeout=%s‘ % curr_datas1[‘wait_timeout‘]
    print ‘interactive_timeout=%s‘ % curr_datas1[‘interactive_timeout‘]

    new_connect(info=‘第一个连接修改global wait_timeout为:%s之后,登录新的连接的session级别的超时信息如下:‘ % wait_timeout,timeout=wait_timeout)

    restore()

    curr_cur.close()
    curr_cur = curr_conn.cursor()
    print "在第一个连接中修改global interactive_timeout为:%s" % interactive_timeout
    curr_cur.execute("set global interactive_timeout=%s;" % interactive_timeout)
    curr_cur.execute("show variables like ‘%timeout%‘;")
    curr_datas2 = curr_cur.fetchall()
    curr_datas2 = dict(curr_datas2)
    
    print "%s
第一个连接保持不断开的session级别的超时信息:" % (‘-‘ * 100) 
    print ‘wait_timeout=%s‘ % curr_datas2[‘wait_timeout‘]
    print ‘interactive_timeout=%s‘ % curr_datas2[‘interactive_timeout‘]

    new_connect(info=‘第一个连接修改global interactive_timeout为:%s之后,登录新的连接的session级别的超时信息如下:‘ % interactive_timeout,timeout=interactive_timeout)

    curr_cur.close()
    curr_conn.close()


def restore():
    print "开启新的连接执行恢复参数初始设置----------------------"
    rest_conn = MySQLdb.connect(user=mysql_user,passwd=mysql_password,host=mysql_ip)
    rest_cur = rest_conn.cursor()
    rest_cur.execute("set global wait_timeout=%s,interactive_timeout=%s;" % (rest_wait_timeout,rest_interactive_timeout))

    rest_cur.close()
    rest_conn.close()
   

print ‘=‘ * 100
try:
    current_connect()
except Exception,e:
    print e
else:
    restore()

print ‘=‘ * 100
  • 跑一下这个脚本,打印结果如下:

#python test_timeout.py 
====================================================================================================
在第一个连接中修改global wait_timeout为:5
----------------------------------------------------------------------------------------------------
第一个连接保持不断开的session级别的超时信息:
wait_timeout=5
interactive_timeout=172800
-------------------------------------------------- 
第一个连接修改global wait_timeout为:5之后,登录新的连接的session级别的超时信息如下:
wait_timeout=5
interactive_timeout=172800
sleep 5 秒之后再次执行sql---
(2013, ‘Lost connection to MySQL server during query‘)
====================================================================================================
  • 从上面的结果中可以看到,第一个会话中修改global wait_timeout=5之后,新的连接上来,超过5秒没有发送新的数据包,连接就被断开。

  • 综合1.3小节演示结果来看
  • MySQL命令行客户端下:global级别的interactive_timeout修改对当前连接不生效,但能影响新的连接的globa interactive_timeout、session interactive_timeout、session wait_timeout数值
  • MySQL命令行客户端下:session级别的interactive_timeout的修改除了能使session interactive_timeout数值改变之外没有什么作用
  • MySQL命令行客户端下:global级别的wait_timeout的修改除了能使global wait_timeout数值改变之外没有什么作用
  • MySQL命令行客户端下:session级别的wait_timeout能改变session wait_timeout数值其对当前连接生效。
  • python MySQL driver:修改global wait_timeout对当前连接不生效,但能影响新的连接的global wait_timeout、session wait_timeout
  • python MySQL driver:修改session wait_timeout只对当前连接生效
  • python MySQL driver:修改global interactive_timeout对当前连接不生效,能影响新的连接的global interactive_timeout、session interactive_timeout
  • python MySQL driver:修改session interactive_timeout除了能使session interactive_timeout数值改变之外没有什么作用

  • PS:思考?
  • 为什么MySQL命令行客户端中新的连接的session wait_timeout不是使用的global wait_timeout的值,而是使用的interactive_timeout的值?但是,为什么python MySQL driver中,新的连接的session wait_timeout就是按照正常的逻辑使用的是global wait_timeout的值?这里先卖个关子,问题的答案得去源码中找,参考链接:http://dev.mysql.com/doc/refman/5.6/en/mysql-real-connect.html

1.4. net_write_timeout

  • mysql服务端向客户端写(发送)数据时,服务端等待客户端响应的超时时间,当服务端正在写数据到客户端时,net_write_timeout控制何时超时
  • 对于这个参数,session和global级别并没有什么特别,session级别只对当前连接生效,global级别只对新的连接生效。默认值是60S
  • 下面使用tc命令模拟网络延迟来进行演示

## 使用sysbench在MySQL server上造数一张500W行数据的表

## tc命令对MySQL客户端的网卡加延迟
tc qdisc add dev eth0 root netem delay 1s

## MySQL 客户端登录server,修改net_write_timeout参数为1S
mysql -uqbench -pqbench -h 10.10.30.68
mysql > set global net_write_timeout=1;
Query OK, 0 rows affected (0.00 sec)

## 在MySQL客户端使用mysqldump备份
[[email protected]20bc83fd-1489-4b60-976b-d1823e7dc36e data] # time mysqldump -uqbench -pqbench -h 10.10.30.68 --single-transaction --master-data=2  sbtest  sbtest2 > sbtest2.sql
Warning: Using a password on the command line interface can be insecure.
mysqldump: Error 2013: Lost connection to MySQL server during query when dumping table `sbtest2` at row: 85  #从这里可以看到,不到一分钟时间,连接就被断开了

real    0m54.049s
user    0m0.009s
sys 0m0.011s

## MySQL客户端登录server,修改net_write_timeout参数为默认的60S
mysql -uqbench -pqbench -h 10.10.30.68
mysql > set global net_write_timeout=60;
Query OK, 0 rows affected (0.00 sec)

## 在MySQL客户端使用mysqldump重试备份
[[email protected]20bc83fd-1489-4b60-976b-d1823e7dc36e data]# time mysqldump -uqbench -pqbench -h 10.10.30.68 --single-transaction --master-data=2  sbtest  sbtest2 > sbtest2.sql
Warning: Using a password on the command line interface can be insecure.

real    14m41.744s
user    0m18.662s
sys 0m7.886s

[[email protected]20bc83fd-1489-4b60-976b-d1823e7dc36e data]# ls -lh
total 963M
drwxr-xr-x 12 mysql mysql  137 Dec 30 15:04 mysqldata1
drwxr-xr-x  2 mysql mysql    6 Dec 30 15:04 recovery
-rw-r--r--  1 root  root  963M Dec 30 15:30 sbtest2.sql  #这里可以看到,消耗15分钟之后,备份成功,备份文件大小接近1G
[[email protected]20bc83fd-1489-4b60-976b-d1823e7dc36e data]# 

1.5. net_read_timeout

  • mysql服务端从客户端读取(接收)数据时,服务端等待客户端响应的超时时间,当服务端正在从客户端读取数据时,net_read_timeout控制何时超时
  • 对于这个参数,session和global级别并没有什么特别,session级别只对当前连接生效,global级别只对新的连接生效。默认值是30S
  • 下面接着1.4小节进行演示,使用1.4小节中的备份结果导入数据库

## MySQL客户端登录server,先查看一下net_read_timeout参数的侄
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 15453
Server version: 5.6.30-log MySQL Community Server (GPL)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;‘ or ‘h‘ for help. Type ‘c‘ to clear the current input statement.

mysql> show variables like ‘%net_read_timeout%‘;
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| net_read_timeout | 30    |
+------------------+-------+
1 row in set (0.00 sec)

mysql> 

## 现在,把1.4小节备份出来的sbtest2.sql文件导入server中的sbtest库
[[email protected]20bc83fd-1489-4b60-976b-d1823e7dc36e data]# time mysql -uqbench -pqbench -h 10.10.30.68 sbtest < sbtest2.sql 
Warning: Using a password on the command line interface can be insecure.

real    37m17.831s  #导入成功,耗时38分钟左右
user    0m22.797s
sys 0m3.436s

## 现在,使用MySQL客户端登录server,修改net_read_timeout参数
[[email protected]555f12f7-850d-4f42-867c-2d12890beb40 data]# mysql -uqbench -pqbench -h 10.10.30.68
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 17040
Server version: 5.6.30-log MySQL Community Server (GPL)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;‘ or ‘h‘ for help. Type ‘c‘ to clear the current input statement.

mysql> set global net_read_timeout=1;
Query OK, 0 rows affected (0.00 sec)

mysql> 

## 修改tc模拟规则,模拟丢包10%,损坏包20%,延迟2秒,包乱序20%
tc qdisc del dev eth0 root
tc qdisc add dev eth0 root netem corrupt 20% loss 10% delay 2s reorder 20%

## 使用备份文件再次尝试导入
time mysql -uqbench -pqbench -h 10.10.30.68 sbtest < sbtest2.sql 

## 很囧的一个事情发生了。此时反复查看server端的processlist,只发现客户端连接上来了,但是一直是sleep状态
mysql> show processlist;
+-------+--------+-------------------+--------+---------+------+-------+------------------+
| Id    | User   | Host              | db     | Command | Time | State | Info             |
+-------+--------+-------------------+--------+---------+------+-------+------------------+
| 17129 | qbench | 10.10.30.78:16167 | sbtest | Sleep   |  207 |       | NULL             |
| 17159 | qbench | 10.10.30.68:47148 | NULL   | Query   |    0 | init  | show processlist |
+-------+--------+-------------------+--------+---------+------+-------+------------------+
2 rows in set (0.00 sec)

mysql> kill 17129;  ## 尝试kill掉这个连接
Query OK, 0 rows affected (0.00 sec)

mysql> show processlist;
+-------+--------+-------------------+------+---------+------+-------+------------------+
| Id    | User   | Host              | db   | Command | Time | State | Info             |
+-------+--------+-------------------+------+---------+------+-------+------------------+
| 17159 | qbench | 10.10.30.68:47148 | NULL | Query   |    0 | init  | show processlist |
+-------+--------+-------------------+------+---------+------+-------+------------------+
1 row in set (0.00 sec)

mysql> use sbtest
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select count(*) from sbtest2;  ## 然后再查询一下sbtest2表的数据,发现是空的
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

## 此时,查看客户端的导入数据的连接
[[email protected]20bc83fd-1489-4b60-976b-d1823e7dc36e data]# time mysql -uqbench -pqbench -h 10.10.30.68 sbtest < sbtest2.sql 
ERROR 2006 (HY000) at line 47: MySQL server has gone away  ## 发现断开了,囧。。

real    5m42.419s
user    0m0.031s
sys 0m0.017s
  • 从上面的结果中可以看到:修改net_read_timeout=1,并在客户端导入数据到server的时候,并没有如预期的超时断开客户端连接。猜测可能是客户端导入数据到server端的时候,server端接收包超时之后没有发起kill掉客户端的操作,所以不手动执行一把kill的话,客户端一直在那里不动,而server端的连接线程也一直处于sleep状态

  • PS:
  • 1.4和1.5小节演示用数据库帐号权限:SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, INDEX, ALTER, SUPER, LOCK TABLES, PROCESS
  • 与net_read_timeout和net_write_timeout相关的还有一个参数,net_retry_count,官方描述如下:
    If a read or write on a communication port is interrupted, retry this many times before giving up.


2、锁类超时

2.1. innodb_lock_wait_timeout

  • 官方描述:
    The length of time in seconds an InnoDB transaction waits for a row lock before giving up
  • innodb使用这个参数能够有效避免在资源有限的情况下产生太多的锁等待;指的是事务等待获取资源时等待的最长时间,超过这个时间还未分配到资源则会返回应用失败;参数的时间单位是秒,最小可设置为1s(一般不会设置得这么小),最大可设置1073741824秒(34年,一条语句锁等待超过30分钟估计业务该有反馈了),默认安装时这个值是50s,超过这个时间会报 ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

## 第一个会话,创建测试数据,并设置innodb_lock_wait_timeout=1
MySQL [(none)]> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MySQL [test]> create table test(id int);
Query OK, 0 rows affected (0.03 sec)

MySQL [test]> insert into test values(1);
Query OK, 1 row affected (0.01 sec)

MySQL [test]> select * from test;
+------+
| id   |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

MySQL [test]> set innodb_lock_wait_timeout=1;
Query OK, 0 rows affected (0.00 sec)

MySQL [test]> 

## 打开第二个会话,注意第二个会要重连,然后打开一个事务,使用select...for update不提交
MySQL [test]> use test
Database changed
MySQL [test]> begin;
Query OK, 0 rows affected (0.00 sec)

MySQL [test]> select * from test where id=1 for update;
+------+
| id   |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

MySQL [test]> 

## 此时 回到第一个会话中,执行相同的select..for update语句,等到1S之后会话超时终止
MySQL [test]> select * from test where id=1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
MySQL [test]> 
  • 对于这个参数,session和global级别并没有什么特别,session级别只对当前连接生效,global级别只对新的连接生效
  • 从上面的结果中可以看到,把innodb_lock_wait_timeout设置为1S之后,对于同一行的操作,锁等待超过1S就被终止事务了
  • PS:
  • 测试结果是在RR隔离级别下基于innodb表的DML操作

2.2. innodb_rollback_on_timeout

  • 官方描述:
    In MySQL 5.6, InnoDB rolls back only the last statement on a transaction timeout by default. If --innodb_rollback_on_timeout is specified, a transaction timeout causes InnoDB to abort and roll back the entire transaction
  • 默认情况下innodb_lock_wait_timeout 超时后只是超时的sql执行失败,整个事务并不回滚,也不做提交,如需要事务在超时的时候回滚,则需要设置innodb_rollback_on_timeout=ON,该参数默认为OFF

## 先测试一下innodb_rollback_on_timeout为默认值时的情况,打开第一个会话,显式开启一个事务,插入几行测试数据,不提交:
MySQL [test]> show variables like ‘%rollback%‘;
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_rollback_on_timeout | OFF   |
| innodb_rollback_segments   | 128   |
+----------------------------+-------+
2 rows in set (0.00 sec)

MySQL [test]> use test
Database changed
MySQL [test]> show tables;
Empty set (0.00 sec)

MySQL [test]> create table test(id int);
Query OK, 0 rows affected (0.05 sec)

MySQL [test]> begin;
Query OK, 0 rows affected (0.00 sec)

MySQL [test]>insert into test(id) values(1),(2),(3),(4);
Query OK, 1 row affected (0.00 sec)

MySQL [test]> select * from test;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
+------+
4 rows in set (0.00 sec)

## 现在,打开第二个会话,显式开启一个事务,并插入数据5,不提交
MySQL [(none)]> use test
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
MySQL [(none)]> begin;
Query OK, 0 rows affected (0.00 sec)

MySQL [test]> insert into test values(5);
Query OK, 1 row affected (0.00 sec)

MySQL [test]> select * from test;
+------+
| id   |
+------+
|    5 |
+------+
2 rows in set (0.00 sec)

## 再回到第一个会话中,更新id为5的数据行为6
MySQL [test]> update test set id=6 where id=5;  #因为第二个会话插入第=5这行数据时,对5及其以后的范围加了锁,也没有提交,所以这个这里的操作需要进行锁等待
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
MySQL [test]> select * from test ;  #这里可以看到,超时之后,第一个会话最开始在显式事务中插入的几行数据并没有回滚
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
+------+
4 rows in set (0.00 sec)


##此时,你需要自行决定会话1中插入的数据是要提交,还是需要回滚,当然,如果断开连接,事务会自动回滚,为了方便后续的测试,先在两个会话中都做rollback操作
  • 从上面的结果中可以看到,默认情况下innodb_rollback_on_timeout为OFF,此时超时终止的会话中的事务DML修改的数据不会自动回滚。

  • 现在,把innodb_rollback_on_timeout参数在my.cnf中加入并改为ON,重启mysql,再次插入相同数据试试看


## 第一个会话中显示开启一个事务,插入几行数据,不提交
MySQL [test]> show variables like ‘%rollback%‘;
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_rollback_on_timeout | ON   |
| innodb_rollback_segments   | 128   |
+----------------------------+-------+
2 rows in set (0.00 sec)

MySQL [test]> use test
Database changed

MySQL [test]> begin;
Query OK, 0 rows affected (0.00 sec)

MySQL [test]>insert into test(id) values(1),(2),(3),(4);
Query OK, 1 row affected (0.00 sec)

MySQL [test]> select * from test;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
+------+
4 rows in set (0.00 sec)

## 现在,打开第二个会话,显式开启一个事务,并插入数据5,不提交
MySQL [(none)]> use test
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
MySQL [(none)]> begin;
Query OK, 0 rows affected (0.00 sec)

MySQL [test]> insert into test values(5);
Query OK, 1 row affected (0.00 sec)

MySQL [test]> select * from test;
+------+
| id   |
+------+
|    5 |
+------+
2 rows in set (0.00 sec)

## 再回到第一个会话中,更新id为5的数据行为6
MySQL [test]> update test set id=6 where id=5;  #因为第二个会话插入第=5这行数据时,对5及其以后的范围加了锁,也没有提交,所以这个这里的操作需要进行锁等待
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
MySQL [test]> select * from test ;  #这里可以看到,超时之后,第一个会话最开始在显式事务中插入的几行数据已经回滚
Empty set (0.00 sec)
  • 从上面的结果中可以看到,把参数innodb_rollback_on_timeout设置为ON之后(注意,这个变量是只读变量,需要添加到my.cnf中并重启mysql),如果一个事务发生锁等待超时,那么这个事务没有提交的数据都会被回滚掉。

2.3. lock_wait_timeout

  • 官方描述:
    This variable specifies the timeout in seconds for attempts to acquire metadata locks.
  • 这里不得不提一下2.1小节的innodb_lock_wait_timeout超时参数,相信有不少人是没有搞太清楚这两者的区别,从字面上来看,前者是innodb的dml操作的行级锁的等待时间 后面是获取MDL锁的等待时间,默认值是31536000秒=1年。那么,下面来演示一把吧

## 打开第一个会话,显示开启一个会话,执行select...for update语句,不提交事务
MySQL [test]> begin;
Query OK, 0 rows affected (0.00 sec)

MySQL [test]> select * from test for update;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|    5 |
+------+
5 rows in set (0.00 sec)

## 现在,打开第二个会话,修改session lock_wait_timeout=5,并执行DDL语句
MySQL [test]> set lock_wait_timeout=5;
Query OK, 0 rows affected (0.00 sec)

MySQL [test]> use test
Database changed

MySQL [test]> alter table test add column test varchar(100);  #DDL语句执行被阻塞,5秒之后超时终止
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
MySQL [test]> 
  • 从上面的结果中可以看到,DDL语句的超时时间是受lock_wait_timeout参数控制的
  • PS:注意,凡是需要获取MDL锁的操作都受到这个超时参数的影响,不单单是DDL语句,包含在表上的DML、DDL操作,以及视图、存储过程、存储函数、lock table,flush table with read lock语句等。但不适用于隐式访问系统表的语句,如:grant和revoke等

3、复制类超时

3.1. delayed_insert_timeout

  • 官方描述:
    How many seconds an INSERT DELAYED handler thread should wait for INSERT statements beforeterminating.
  • 为MyISAM INSERT DELAY设计的超时参数,表示INSERT DELAY handler线程在INSERT DELAY语句终止前等待这个INSERT语句的时间,注意是表示insert delay延迟插入的超时时间,不是insert语句。默认值是300S,从5.6.7开始被弃用(因为delayed insert功能被弃用)后续版本将移除。

3.2. rpl_semi_sync_master_timeout

  • 官方描述:
    A value in milliseconds that controls how long the master waits on a commit for acknowledgment from a slave before timing out and reverting to asynchronous replication. The default value is 10000 (10 seconds).

This variable is available only if the master-side semisynchronous replication plugin is installed.

  • 为semi-sync复制时,主库在某次事务提交时,如果等待超过rpl_semi_sync_master_timeout多秒之后仍然没有接收到任何从库做回包响应,那么主库自动降级为异步复制模式,当主库探测到有备库恢复回包时,主库自动恢复到semi-sync复制模式。默认值为10000毫秒=10秒

3.3. rpl_stop_slave_timeout

  • 官方描述:
    In MySQL 5.6.13 and later, you can control the length of time (in seconds) that STOP SLAVE waits before timing out by setting this variable. This can be used to avoid deadlocks between STOP SLAVE and other slave SQL statements using different client connections to the slave. The maximum and default value of rpl_stop_slave_timeout is 31536000 seconds (1 year). The minimum is 2 seconds.
  • 5.6.13之后引入的参数,控制stop slave 的执行时间,在重放一个大的事务的时候,突然执行stop slave,命令 stop slave会执行很久,这个时候可能产生死锁或阻塞,严重影响性能,可以通过rpl_stop_slave_timeout参数控制stop slave 的执行时间。默认值是31536000秒=1年

3.4. slave_net_timeout

  • 官方描述:
    The number of seconds to wait for more data from a master/slave connection before aborting the read.
  • Slave判断主库是否挂掉的超时设置,在设定时间内依然没有获取到Master的回应就认为Master已经挂掉了,后续根据超时重连参数设置进行重连主库的操作。默认值:3600S

4、IO类超时

4.1. innodb_flush_log_at_timeout

  • 官方描述:
    Write and flush the logs every N seconds. innodb_flush_log_at_timeout was introduced in MySQL 5.6.6. It allows the timeout period between flushes to be increased in order to reduce flushing and avoid impacting performance of binary log group commit. Prior to MySQL 5.6.6, flushing frequency was once per second. The default setting for innodb_flush_log_at_timeout is also once per second.
  • 5.6.6引入,参数innodb_flush_log_at_trx_commit=1时,此超时参数不起作用,当innodb_flush_log_at_trx_commit=0/2时才起作用。5.6.6之后表示每innodb_flush_log_at_timeout秒一次的频率刷新redo log(在5.6.6之前是固定每秒一次刷新redo log,5.6.6之后刷新频率可以通过这个参数设置,当然,这个参数本身默认值也是1S)。

以上是关于MySQL - 各种超时时间 - 学习与探究的主要内容,如果未能解决你的问题,请参考以下文章

探究各种学习率策略--模拟学习率变化过程

sqlalchemy + MySQL 连接超时

MySQL 各种超时参数的含义

phpMyAdmin 有时在登录时给我“操作超时”

Linux下超时重传时间(RTO)的实现探究

MySQL 各种超时参数的含义