本篇内容介绍了“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:

staticSys_var_ulongSys_interactive_timeout(vio_io_wait"interactive_timeout","Thenumberofsecondstheserverwaitsforactivityonaninteractive""connectionbeforeclosingit",SESSION_VAR(net_interactive_timeout),CMD_LINE(REQUIRED_ARG),VALID_RANGE(1,LONG_TIMEOUT),DEFAULT(NET_WAIT_TIMEOUT),BLOCK_SIZE(1));

wait_timeout:

staticSys_var_ulongSys_net_wait_timeout("wait_timeout","Thenumberofsecondstheserverwaitsforactivityona""connectionbeforeclosingit",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类型的客户端连接才会做覆盖。

栈帧如下:

#0server_mpvio_update_thd(thd=0x7ffe7c012940,mpvio=0x7fffec0f6140)at/root/mysqlall/percona-server-locks-detail-5.7.22/sql/auth/sql_authentication.cc:2014#10x0000000000f01787inacl_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#20x0000000001571149incheck_connection(thd=0x7ffe7c012940,extra_port_connection=false)at/root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_connect.cc:1295#30x00000000015712dcinlogin_connection(thd=0x7ffe7c012940,extra_port_connection=false)at/root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_connect.cc:1352#40x0000000001571bfeinthd_prepare_connection(thd=0x7ffe7c012940,extra_port_connection=false)at/root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_connect.cc:1516#50x000000000170e642inhandle_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;//不需要做操作直接returnnet->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就起作用了。整个栈帧如下:

#0vio_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#10x0000000001e4d5f6invio_socket_io_wait(vio=0x7ffe7c015520,event=VIO_IO_EVENT_READ)at/root/mysqlall/percona-server-locks-detail-5.7.22/vio/viosocket.c:116#20x0000000001e4d6d2invio_read(vio=0x7ffe7c015520,buf=0x7ffe7c061c10"\001",size=4)at/root/mysqlall/percona-server-locks-detail-5.7.22/vio/viosocket.c:171#30x00000000014c6cebinnet_read_raw_loop(net=0x7ffe7c028440,count=4)at/root/mysqlall/percona-server-locks-detail-5.7.22/sql/net_serv.cc:672#40x00000000014c6ec2innet_read_packet_header(net=0x7ffe7c028440)at/root/mysqlall/percona-server-locks-detail-5.7.22/sql/net_serv.cc:756#50x00000000014c6fcbinnet_read_packet(net=0x7ffe7c028440,complen=0x7fffec0c5c58)at/root/mysqlall/percona-server-locks-detail-5.7.22/sql/net_serv.cc:822#60x00000000014c715einmy_net_read(net=0x7ffe7c028440)at/root/mysqlall/percona-server-locks-detail-5.7.22/sql/net_serv.cc:899#70x00000000014de010inProtocol_classic::read_packet(this=0x7ffe7c027bf8)at/root/mysqlall/percona-server-locks-detail-5.7.22/sql/protocol_classic.cc:808#80x00000000014de514inProtocol_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#90x00000000015c5699indo_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:/*Onerror,-1isreturned.*/break;case0:/*Seterrnotoindicateatimeouterror.(ThisisnotcompiledinonWIN32.)*/errno=SOCKET_ETIMEDOUT;break;default:/*EnsurethattherequestedI/Oeventhascompleted.*/DBUG_ASSERT(pfd.revents&revents);break;}

因此整个步骤就是

loop

做wait_timeout参数检查并且赋值。

堵塞接受命令由poll函数实现,通过poll函数的超时参数也实现了空闲等待超时。(如果不发送命令就堵塞在这里)

命令来到退出堵塞。

再次做wait_timeout参数检查并且赋值。

执行命令。

goto loop

五、测试

我这里就用mysql客户端和pymysql进行交互和非交互连接的测试。

交互式mysql客户端会话interactive_timeout 参数覆盖wait_timeout参数

mysql>showvariableslike'wait_timeout%';+---------------+-------+|Variable_name|Value|+---------------+-------+|wait_timeout|28800|+---------------+-------+1rowinset(0.02sec)mysql>showvariableslike'interactive_timeout';+---------------------+-------+|Variable_name|Value|+---------------------+-------+|interactive_timeout|28800|+---------------------+-------+1rowinset(0.01sec)mysql>setglobalinteractive_timeout=20;QueryOK,0rowsaffected(0.00sec)mysql>exitBye[root@gp1log]#/mysqldata/mysql3340/bin/mysqlWelcometotheMySQLmonitor.Commandsendwith;or\g.YourMySQLconnectionidis6Serverversion:5.7.22-22-debug-logSourcedistributionCopyright(c)2009-2018PerconaLLCand/oritsaffiliatesCopyright(c)2000,2018,Oracleand/oritsaffiliates.Allrightsreserved.OracleisaregisteredtrademarkofOracleCorporationand/oritsaffiliates.Othernamesmaybetrademarksoftheirrespectiveowners.Type'help;'or'\h'forhelp.Type'\c'toclearthecurrentinputstatement.mysql>showvariableslike'interactive_timeout';+---------------------+-------+|Variable_name|Value|+---------------------+-------+|interactive_timeout|20|+---------------------+-------+1rowinset(0.01sec)mysql>showvariableslike'wait_timeout';+---------------+-------+|Variable_name|Value|+---------------+-------+|wait_timeout|20|+---------------+-------+1rowinset(0.02sec)

交互式mysql客户端会话登陆期间修改interactive_timeout不生效,更改wait_timeout生效。

mysql>showvariableslike'interactive_timeout';+---------------------+-------+|Variable_name|Value|+---------------------+-------+|interactive_timeout|28800|+---------------------+-------+1rowinset(0.02sec)mysql>showvariableslike'wait_timeout';+---------------+-------+|Variable_name|Value|+---------------+-------+|wait_timeout|28800|+---------------+-------+1rowinset(0.02sec)mysql>setinteractive_timeout=5;QueryOK,0rowsaffected(0.00sec)mysql>showvariableslike'wait_timeout';+---------------+-------+|Variable_name|Value|+---------------+-------+|wait_timeout|28800|+---------------+-------+1rowinset(0.01sec)mysql>showvariableslike'interactive_timeout';+---------------------+-------+|Variable_name|Value|+---------------------+-------+|interactive_timeout|5|+---------------------+-------+1rowinset(0.02sec)等待5秒,并未生效mysql>selectsysdate();+---------------------+|sysdate()|+---------------------+|2019-02-2817:24:29|+---------------------+1rowinset(0.00sec)mysql>setwait_timeout=5;QueryOK,0rowsaffected(0.00sec)等待5秒发现断开了mysql>showvariableslike'wait_timeout';ERROR2006(HY000):MySQLserverhasgoneawayNoconnection.Tryingtoreconnect...Connectionid:10

使用python连接非交互式客户端interactive_timeout 参数不会覆盖wait_timeout参数

我们可以简单的写一个python脚本如下:

importsocketimportpymysql.cursorsimportpsutilimportsubprocessmysql_con={"host":"192.168.99.95","port":3340,"user":"pycon","passwd":"gelc123","db":"test"}defmain():sqlwait="showvariableslike'wait_timeout'"sqlinter="showvariableslike'interactive_timeout'"sql_c_inter="setglobalinteractive_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("beforechange:{}".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("afterchange:{}".format(ret_wait+ret_inter))##恢复值sql_c_inter="setglobalinteractive_timeout=28800"cursor.execute(sql_c_inter)connect.close()#关闭连接##程序开始if__name__=='__main__':main()

得到的测试结果如下:

beforechange:('wait_timeout','28800','interactive_timeout','28800')afterchange:('wait_timeout','28800','interactive_timeout','10')

如果是交互是客户端会话的话wait_timeout也应该是10。

“MySQL中参数wait_timeout和interactive_timeout以及空闲超时的实现方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!