MySQL:参数wait_timeout和interactive_timeout以及空闲超时的实现【转】
一、參數意思
這里簡單解釋一下兩個參數,含義如下:
-
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().
-
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_timeout value, depending on the type of client (as defined by the CLIENT_INTERACTIVE connect option to mysql_real_connect()).
他們都是session/global級別的,簡單的說前者用于描述交互式的客戶端的空閑超時,后者用于非交互式的客戶端的空閑超時。但是這里也揭示了,如果是交互式客戶端連接的session那么wait_timeout將被interactive_timeout覆蓋掉,換句話說如果是非交互式的客戶端連接的session將不會使用interactive_timeout覆蓋掉wait_timeout,也就是interactive_timeout沒有任何作用了。
摘自官網內容:
-
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().
interactive_timeout控制交互式連接的空閑時間。如果調用mysql的mysql_real_connect()函數的時候,使用了CLIENT_INTERACTIVE參數,該連接就定義為交互式連接。
-
wait_timeout: The number of seconds the server waits for activity on a noninteractive connection before closing it.
翻譯:wait_timeout控制非交互連接的閑置時間。
-
On thread startup, the session waittimeout value is initialized from the globalwait_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()). See also?interactive_timeout.
翻譯:在連接建立的時候,session級別的wait_timeout會根據連接的分類來選擇是繼承global級別的interactive_timeout的值和global級別的wait_timeout的值。
?
二、參數內部表示
?
-
interactive_timeout:
?
static Sys_var_ulong Sys_interactive_timeout( vio_io_wait
? ? ? "interactive_timeout",
? ? ? "The number of seconds the server waits for activity on an interactive "
? ? ? "connection before closing it",
? ? ? SESSION_VAR(net_interactive_timeout),
? ? ? CMD_LINE(REQUIRED_ARG),
? ? ? VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(NET_WAIT_TIMEOUT), BLOCK_SIZE(1));
-
wait_timeout:
?
static Sys_var_ulong Sys_net_wait_timeout(
? ? ? "wait_timeout",
? ? ? "The number of seconds the server waits for activity on a "
? ? ? "connection before closing it",
? ? ? SESSION_VAR(net_wait_timeout), CMD_LINE(REQUIRED_ARG),
? ? ? VALID_RANGE(1, IF_WIN(INT_MAX32/1000, LONG_TIMEOUT)),
? ? ? DEFAULT(NET_WAIT_TIMEOUT), BLOCK_SIZE(1));
我們可以看到內部而言參數interactive_timeout表示為net_interactive_timeout,wait_timeout表示為net_wait_timeout。
?
三、interactive_timeout覆蓋wait_timeout
實際上,這個操作只會在用戶登陸的時候才出現函數對應server_mpvio_update_thd,如下:
server_mpvio_update_thd(THD *thd, MPVIO_EXT *mpvio) do_command
{
?thd->max_client_packet_length= mpvio->max_client_packet_length;
?if (mpvio->protocol->has_client_capability(CLIENT_INTERACTIVE)) //這里做判斷
? ?thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;//這里覆蓋
這里我們可以明確看到有覆蓋操作,并且也能看到這里只有if條件是client_interactive類型的客戶端連接才會進行覆蓋。
棧幀如下:
#0 ?server_mpvio_update_thd (thd=0x7ffe7c012940, mpvio=0x7fffec0f6140) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/auth/sql_authentication.cc:2014
#1 ?0x0000000000f01787 in acl_authenticate (thd=0x7ffe7c012940, command=COM_CONNECT, extra_port_connection=false)
? ?at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/auth/sql_authentication.cc:2246
#2 ?0x0000000001571149 in check_connection (thd=0x7ffe7c012940, extra_port_connection=false)
? ?at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_connect.cc:1295
#3 ?0x00000000015712dc in login_connection (thd=0x7ffe7c012940, extra_port_connection=false)
? ?at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_connect.cc:1352
#4 ?0x0000000001571bfe in thd_prepare_connection (thd=0x7ffe7c012940, extra_port_connection=false)
? ?at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_connect.cc:1516
#5 ?0x000000000170e642 in handle_connection (arg=0x6781c30) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/conn_handler/connection_handler_per_thread.cc:306
那么,我們這里可以得到一個結論:只在登陸的時候會判斷連接是否是交互式的。如果是,則覆蓋掉參數wait_timeout,但是一旦連接后將不會發生覆蓋操作,即便我們再次修改interactive_timeout的值也不會覆蓋,后面我們看到實際上生效的參數只有wait_timeout。
?
四、超時的實現
實際上每次執行任何一個命令都會做一次wait_timeout值的重新檢查和給網絡read_timeout參數賦值。在函數do_command中我們可以發現步驟my_net_set_read_timeout(net, thd->get_wait_timeout()),這個步驟就是將我們的wait_timeout賦值給網絡參數read_timeout,其中包含片段如下:
if (net->read_timeout == timeout) //如果read_timeout和wait_timeout相等
? ?DBUG_VOID_RETURN;//不需要做操作直接return
?net->read_timeout= timeout;//否則進行賦值。
?if (net->vio)
? ?vio_timeout(net->vio, 0, timeout);//這里會進行net->vio.read_timeout的賦值
執行完這個步驟后wait_timeout就生效了,然后就會執行命令。執行完命令后,整個線程會再次回到do_command函數,再做一次my_net_set_read_timeout函數,使其中的wait_timeout參數生效,并且阻塞等待接受命令(后面可以看到是poll實現的),這個時候wait_timeout就起作用了。整個棧幀如下:
#0 ?vio_io_wait (vio=0x7ffe7c015520, event=VIO_IO_EVENT_READ, timeout=10000) at /root/mysqlall/percona-server-locks-detail-5.7.22/vio/viosocket.c:1119
#1 ?0x0000000001e4d5f6 in vio_socket_io_wait (vio=0x7ffe7c015520, event=VIO_IO_EVENT_READ) at /root/mysqlall/percona-server-locks-detail-5.7.22/vio/viosocket.c:116
#2 ?0x0000000001e4d6d2 in vio_read (vio=0x7ffe7c015520, buf=0x7ffe7c061c10 "\001", size=4) at /root/mysqlall/percona-server-locks-detail-5.7.22/vio/viosocket.c:171
#3 ?0x00000000014c6ceb in net_read_raw_loop (net=0x7ffe7c028440, count=4) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/net_serv.cc:672
#4 ?0x00000000014c6ec2 in net_read_packet_header (net=0x7ffe7c028440) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/net_serv.cc:756
#5 ?0x00000000014c6fcb in net_read_packet (net=0x7ffe7c028440, complen=0x7fffec0c5c58) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/net_serv.cc:822#6 ?0x00000000014c715e in my_net_read (net=0x7ffe7c028440) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/net_serv.cc:899
#7 ?0x00000000014de010 in Protocol_classic::read_packet (this=0x7ffe7c027bf8) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/protocol_classic.cc:808
#8 ?0x00000000014de514 in Protocol_classic::get_command (this=0x7ffe7c027bf8, com_data=0x7fffec0c5d70, cmd=0x7fffec0c5d98)
? ?at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/protocol_classic.cc:965
#9 ?0x00000000015c5699 in do_command (thd=0x7ffe7c0268e0) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_parse.cc:960
最終會調入vio_io_wait函數,如下是其中的部分片段,我們可以清楚看到實際上所謂的空閑超時實際上就是我們的poll實現的。
switch ((ret= poll(&pfd, 1, timeout))) ?
?{
?case -1:
? ?/* On error, -1 is returned. */
? ?break;
?case 0:
? ?/*
? ? ?Set errno to indicate a timeout error.
? ? ?(This is not compiled in on WIN32.)
? ?*/
? ?errno= SOCKET_ETIMEDOUT;
? ?break;
?default:
? ?/* Ensure that the requested I/O event has completed. */
? ?DBUG_ASSERT(pfd.revents & revents);
? ?break;
?}
因此整個步驟就是:
-
loop
-
做wait_timeout參數檢查并且賦值。
-
阻塞接受命令由poll函數實現,通過poll函數的超時參數也實現了空閑等待超時。(如果不發送命令就阻塞在這里)
-
命令來到退出阻塞。
-
再次做wait_timeout參數檢查并且賦值。
-
執行命令。
-
goto loop
?
五、測試
我這里就用MySQL客戶端和PyMySQL進行交互和非交互連接的測試。
-
交互式MySQL客戶端會話interactive_timeout 參數覆蓋wait_timeout參數
mysql> show variables like 'wait_timeout%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout ?| 28800 |
+---------------+-------+
1 row in set (0.02 sec)
mysql> show variables like 'interactive_timeout';
+---------------------+-------+
| Variable_name ? ? ? | Value |
+---------------------+-------+
| interactive_timeout | 28800 |
+---------------------+-------+
1 row in set (0.01 sec)
mysql> set global interactive_timeout = 20;
Query OK, 0 rows affected (0.00 sec)
mysql> exit
Bye
[root@gp1 log]# /mysqldata/mysql3340/bin/mysql
Welcome to the MySQL monitor. ?Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.22-22-debug-log Source distribution
Copyright (c) 2009-2018 Percona LLC and/or its affiliates
Copyright (c) 2000, 2018, 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 'interactive_timeout';
+---------------------+-------+
| Variable_name ? ? ? | Value |
+---------------------+-------+
| interactive_timeout | 20 ? ?|
+---------------------+-------+
1 row in set (0.01 sec)
mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout ?| 20 ? ?|
+---------------+-------+
1 row in set (0.02 sec)
-
交互式MySQL客戶端會話登陸期間修改interactive_timeout不生效,更改wait_timeout生效。
?
mysql> show variables like 'interactive_timeout';
+---------------------+-------+
| Variable_name ? ? ? | Value |
+---------------------+-------+
| interactive_timeout | 28800 ?|
+---------------------+-------+
1 row in set (0.02 sec)
mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout ?| 28800 ?|
+---------------+-------+
1 row in set (0.02 sec)
mysql> set interactive_timeout=5;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout ?| 28800 ?|
+---------------+-------+
1 row in set (0.01 sec)
mysql> show variables like 'interactive_timeout';
+---------------------+-------+
| Variable_name ? ? ? | Value |
+---------------------+-------+
| interactive_timeout | 5 ? ? |
+---------------------+-------+
1 row in set (0.02 sec)
等待5秒,并未生效
mysql> select sysdate();
+---------------------+
| sysdate() ? ? ? ? ? |
+---------------------+
| 2019-02-28 17:24:29 |
+---------------------+
1 row in set (0.00 sec)
mysql> set wait_timeout=5;
Query OK, 0 rows affected (0.00 sec)
等待5秒 發現斷開了
mysql> show variables like 'wait_timeout';
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: ? ?10
-
使用Python連接非交互式客戶端interactive_timeout 參數不會覆蓋wait_timeout參數
我們可以簡單的寫一個Python腳本如下:
import socket
import pymysql.cursors
import psutil
import subprocess
mysql_con = {"host":"192.168.99.95","port":3340,"user":"pycon","passwd":"gelc123","db":"test"}
def main():
? ?sqlwait = "show variables like 'wait_timeout'"
? ?sqlinter = "show variables like 'interactive_timeout'"
? ?sql_c_inter = "set global interactive_timeout=10"
? ?connect = pymysql.Connect(host=mysql_con["host"], port=mysql_con["port"], user=mysql_con["user"],
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?passwd=mysql_con["passwd"], db=mysql_con["db"])
? ?cursor = connect.cursor()
? ?##查看初始值
? ?cursor.execute(sqlwait)
? ?ret_wait = cursor.fetchone()
? ?cursor.execute(sqlinter)
? ?ret_inter = cursor.fetchone()
? ?print("before change: {}".format(ret_wait+ret_inter))
? ?##更改值
? ?cursor.execute(sql_c_inter)
? ?connect.close()##關閉連接
? ?##重新登陸開啟連接
? ?connect = pymysql.Connect(host=mysql_con["host"], port=mysql_con["port"], user=mysql_con["user"],
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?passwd=mysql_con["passwd"], db=mysql_con["db"])
? ?cursor = connect.cursor()
? ?cursor.execute(sqlwait)
? ?ret_wait = cursor.fetchone()
? ?cursor.execute(sqlinter)
? ?ret_inter = cursor.fetchone()
? ?print("after change: {}".format(ret_wait+ret_inter))
? ?##恢復值
? ?sql_c_inter = "set global interactive_timeout=28800"
? ?cursor.execute(sql_c_inter)
? ?connect.close()#關閉連接
##程序開始
if __name__ == '__main__':
? ?main()
得到的測試結果如下:
before change: ('wait_timeout', '28800', 'interactive_timeout', '28800')
after change: ('wait_timeout', '28800', 'interactive_timeout', '10')
如果是交互式,是客戶端會話的話wait_timeout也應該是10。
?
六、總結
?
-
內部來講只有wait_timeout參數會傳遞到網絡層設置,而interactive_timeout參數只會在會話登陸的時候判斷是否是交互式客戶端會話如果是則進行wait_timeout=interactive_timeout的覆蓋,如果不是則不生效的。
-
一旦會話登陸成功如果想要會話級別修改超時參數,不管交互式還是非交互式都是修改wait_timeout(set wait_timeout)參數才會生效。
-
內部實現空閑超時是通過poll函數的超時參數實現的。
-
簡單來說interactive_timeout對交互式客戶端連接生效,wait_timeout對非交互式客戶端連接生效。
-
對于參數生效的過程如下:
? ? ? ? ?
| 1、loop 2、做wait_timeout參數檢查并且賦值。 3、阻塞接受命令由poll函數實現,通過poll函數的超時參數也實現了空閑等待超時。(如果不發送命令就阻塞在這里) 4、命令來到退出阻塞。 5、再次做wait_timeout參數檢查并且賦值。 6、執行命令。 7、goto loop |
?
?
總結
1、交互式連接和非交互式連接的空閑時間都是由SESSION級別的wait_timeout時間控制的
2、SESSION級別的wait_timeout值是再連接初始化的時候,根據連接的分類來確定是從GLOBAL 級別的interactive_timeout值繼承還是GLOBAL級別的wait_timeout值繼承
3、SESSION級別的interactive_timeout對連接的閑置時間沒有用處
?
關于“交互式”與“非交互式”連接的區別,請參考:MySQL會話閑置時間控制
轉自
知數堂 https://mp.weixin.qq.com/s/sDPEXjpPJqU6AoFV5vmBow
轉載于:https://www.cnblogs.com/paul8339/p/10608861.html
總結
以上是生活随笔為你收集整理的MySQL:参数wait_timeout和interactive_timeout以及空闲超时的实现【转】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 评论与子评论
- 下一篇: Idea 七步建立Spring Mvc