MySQL:引數wait_timeout和interactive_timeout以及空閒超時的實現
水平有限,如果有誤請指出
原始碼版本:percona 5.7.22
一、引數意思
這裡簡單解釋一下兩個引數含義如下:
-
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:
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函式,如下是其中的部分片段,我們可以清楚看到實際上所謂的空閒超時實際上就是我們的pool實現的。
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/mysqlWelcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 6Server 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 socketimport pymysql.cursorsimport psutilimport 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對非互動式客戶端連線生效。
- 對於引數生效的過程如下:
- loop
- 做wait_timeout引數檢查並且賦值。
- 堵塞接受命令由poll函式實現,透過poll函式的超時引數也實現了空閒等待超時。(如果不傳送命令就堵塞在這裡)
- 命令來到退出堵塞。
- 再次做wait_timeout引數檢查並且賦值。
- 執行命令。
- goto loop
作者微信:gp_22389860
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2637237/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL之wait_timeout和interactive_timeout引數MySqlAI
- 【Mysql】MySQL中interactive_timeout和wait_timeout的區別MySqlAI
- Springboot 連線池wait_timeout超時設定Spring BootAI
- MySQL中wait_timeout的坑MySqlAI
- Runloop有效利用空閒時間OOP
- 隨機森林RF模型超引數的最佳化:Python實現隨機森林模型Python
- 超引數
- MySQL中union和order by同時使用的實現方法MySql
- Laravel同時接收路由引數和查詢字串中的引數Laravel路由字串
- 介面呼叫超時的實現原理
- JVM引數以及用法JVM
- 【超實用攻略】SpringBoot + validator 輕鬆實現全註解式的引數校驗Spring Boot
- mysql和redis實時同步資料怎麼實現MySqlRedis
- mysql備份時候兩個很有用的引數MySql
- oracle建立臨時表空間和資料表空間以及刪除Oracle
- RestTemplate超時引發的血案REST
- MySQL空間函式實現位置打卡MySql函式
- 『動善時』JMeter基礎 — 24、JMeter中使用“使用者引數”實現引數化JMeter
- Spring Boot使用@Async實現非同步呼叫:使用Future以及定義超時Spring Boot非同步
- 閒的蛋疼整理了一下Dockerfile的命令和引數備查Docker
- SpringMVC重定向傳引數的實現SpringMVC
- nginx 常見引數以及重定向引數配置Nginx
- mysql 空值(null)和空字元('')的區別MySqlNull字元
- SpringMVC實現引數校驗SpringMVC
- SpringBoot 引數別名實現Spring Boot
- MySQL 8.0.20 安裝新特性以及一些廢棄引數MySql
- shell中定義變數用雙引號和單引號以及不用引號的區別變數
- 04-超引數
- js時間字串格式化以及url引數處理JS字串格式化
- 訊息的即時推送——net實現、websocket實現以及socket.io實現Web
- mysql interactive_timeout 設定不當一例MySql
- 空閒時間研究一個小功能:winform桌面程式如何實現動態更換桌面圖示ORM
- 引數的定義和引數的傳遞
- fixtrue基礎之params引數實現簡單引數化
- 實現MySQL資料庫的實時備份MySql資料庫
- 關於爬蟲平臺的架構實現和框架的選型(二)--scrapy的內部實現以及實時爬蟲的實現爬蟲架構框架
- Redis實現分散式鎖(setnx、getset、incr)以及如何處理超時情況KJBPRedis分散式
- mysql 時間相關的函式 以及日期和字串互轉MySql函式字串