mysql timeout调研与实测

mysql的timeout有多少种,之间的区别时什么?本文从实测和代码分析的角度验证了不同的超时参数的作用。

接触网络编程我们不得不提的就是超时,TCP建立连接的超时,数据报文发送/接收超时等等,mysql在超时上也做足了功夫。

上面这5个超时是本次调研的重点,当然MySQL绝对不指这5种超时的配置,由于经历和时间有限,本次只谈这5种。

Connect_Timeout
这个比较好理解,字面上看意思是连接超时。"The number of seconds that the mysqld server waits for a connect packet before responding with Bad handshake"。

MySQL连接一次连接需求经过6次“握手”方可成功,任意一次“握手”失败都有可能导致连接失败,如下图所示。
connect_timeout

前三次握手可以简单理解为TCP建立连接所必须的三次握手,MySQL无法控制,更多的受制于不TCP协议的不同实现,后面的三次握手过程超时与connect_timeout有关。简单的测试方法:

Telnet未退出前通过show processlist查看各线程状态可见,当前该连接处于授权认证阶段,此时的用户为“unauthenticated user”。细心的你懂得,千万不要干坏事。

wait_timeout
等待超时,那mysql等什么呢?确切的说是mysql在等用户的请求(query),如果发现一个线程已经sleep的时间超过wait_timeout了那么这个线程将被清理掉,无论是交换模式或者是非交换模式都以此值为准。

注意:wait_timeout是session级别的变量哦,至于session和global变量的区别是什么我不说您也知道。手册上不是明明说wait_timeout为not interactive模式下的超时么?为什么你说无论是交换模式或者非交换模式都以此值为准呢?简单的测试例子如下:

那为什么手册上说在交互模式下使用的是interactive_timeout呢,原因如下:

check_connection函数在建立连接初期,如果为交互模式则将interactive_timeout值赋给wait_timeout,骗您误以为交互模式下等待超时为interactive_timeout 代码如下:

interactive_timeout
上面说了那么多,这里就不再多做解释了。我理解mysql之所以多提供一个目的是提供给用户更灵活的设置空间。

net_write_timeoutite_timeout
看到这儿如果您看累了,那下面您得提提神了,接下来的两个参数才是我们遇到的最大的难题。 "The number of seconds to wait for a block to be written to a connection before aborting the write." 等待将一个block发送给客户端的超时,一般在网络条件比较差的时,或者客户端处理每个block耗时比较长时,由于net_write_timeout导致的连接中断很容易发生。下面是一个模拟的例子:

net_read_timeout
“The number of seconds to wait fprintfor more data from a connection before aborting the read.”。Mysql读数据的时的等待超时,可能的原因可能为网络异常或客户端or服务器端忙无法及时发送或接收处理包。这里我用的是iptables来模拟网络异常,生成一个较大的数据以便于给我充足的时间在load data的过程中去配置iptables规则。

执行完iptables命令后show processlist可以看到load data的连接已经被中断掉了,但因为这里我选择了myisam表,所以

可以看到数据还是被插入了一部分。

net_retry_count
"超时"的孪生兄弟“重试”,时间原因这个我没有进行实际的测试,手册如是说,估且先信它一回。

If a read or write on a communication port is interrupted, retry this many times before giving up. This value should be set quite high on FreeBSD because internal interrupts are sent to all threads.

On Linux, the "NO_ALARM" build flag (-DNO_ALARM) modifies how the binary treats both net_read_timeout and net_write_timeout. With this flag enabled, neither timer cancels the current statement until after the failing connection has been waited on an additional net_retry_count times. This means that the effective timeout value becomes" (timeout setting) × (net_retry_count+1)".

FreeBSD中有效,Linux中只有在build的时候指定NO_ALARM参数时net_retry_count才会起作用。

说明:目前线上使用的版本都未指定NO_ALARM。

---------------------------------------------------------------------------------------------------------------------------------

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

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

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

首先插入三条测试数据

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

当前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)
##事务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不变。

那么如果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

测试例子: 
我们用一个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

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

DROP TABLE t;
ALTER TABLE t ...;
DROP TABLE nt;
ALTER TABLE nt ...;
LOCK TABLE t ... WRITE;1

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

猜你喜欢

转载自blog.csdn.net/dz45693/article/details/79505679