說明:html
接觸網絡編程咱們不得不提的就是超時,TCP創建鏈接的超時,數據報文發送/接收超時等等,mysql在超時上也作足了功夫。mysql
Variable_name Default Value connect_timeout 5 interactive_timeout 28800 net_read_timeout 30 net_write_timeout 60 wait_timeout 28800
上面這5個超時是本次調研的重點,固然MySQL絕對不指這5種超時的配置,因爲經歷和時間有限,本次只談這5種。sql
這個比較好理解,字面上看意思是鏈接超時。」The number of seconds that the mysqld server waits for a connect packet before responding with Bad handshake」。 MySQL鏈接一次鏈接需求通過6次「握手」方可成功,任意一次「握手」失敗都有可能致使鏈接失敗,以下圖所示。編程
前三次握手能夠簡單理解爲TCP創建鏈接所必須的三次握手,MySQL沒法控制,更多的受制於不TCP協議的不一樣實現,後面的三次握手過程超時與connect_timeout有關。簡單的測試方法:服務器
$time telnet mysql_ip_addr port $ time telnet 127.0.0.1 5051 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. ? Connection closed by foreign host. real 0m5.005s #這裏的5秒即mysql默認的鏈接超時 user 0m0.000s sys 0m0.000s
Telnet未退出前經過show processlist查看各線程狀態可見,當前該鏈接處於受權認證階段,此時的用戶爲「unauthenticated user」。細心的你懂得,千萬不要幹壞事。網絡
+--+--------------------+---------------+----+-------+----+----------------+----------------+ |Id|User |Host |db |Command|Time|State |Info | +--+--------------------+---------------+----+-------+----+----------------+----------------+ | 6|root |localhost |NULL|Query | 0|NULL |show processlist| | 7|unauthenticated user|localhost:58598|NULL|Connect|NULL|Reading from net|NULL | +--+--------------------+---------------+----+-------+----+----------------+----------------+
等待超時,那mysql等什麼呢?確切的說是mysql在等用戶的請求(query),若是發現一個線程已經sleep的時間超過wait_timeout了那麼這個線程將被清理掉,不管是交換模式或者是非交換模式都以此值爲準。session
注意:wait_timeout是session級別的變量哦,至於session和global變量的區別是什麼我不說您也知道。手冊上不是明明說wait_timeout爲not interactive模式下的超時麼?爲何你說不管是交換模式或者非交換模式都以此值爲準呢?簡單的測試例子以下:tcp
mysql> show variables like "%timeout%"; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | connect_timeout | 5 | | delayed_insert_timeout | 300 | | innodb_lock_wait_timeout | 50 | | innodb_rollback_on_timeout | OFF | | interactive_timeout | 28800 | | net_read_timeout | 30 | | net_write_timeout | 60 | | slave_net_timeout | 3600 | | table_lock_wait_timeout | 50 | | wait_timeout | 28800 | +----------------------------+-------+ 10 rows in set (0.00 sec) Date : 2012-2-24 Fri 22:41:24 #可見我把interactive_timeout改成1秒後通過了4秒的時間沒有任何請求,鏈接卻沒有被斷開。爲了驗證wait_timeout我再把interactive_timeout改回來 mysql> set interactive_timeout=28800; Query OK, 0 rows affected (0.00 sec) Date : 2012-2-24 Fri 22:43:43 mysql> show variables like "%timeout%"; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | connect_timeout | 5 | | delayed_insert_timeout | 300 | | innodb_lock_wait_timeout | 50 | | innodb_rollback_on_timeout | OFF | | interactive_timeout | 28800 | | net_read_timeout | 30 | | net_write_timeout | 60 | | slave_net_timeout | 3600 | | table_lock_wait_timeout | 50 | | wait_timeout | 28800 | +----------------------------+-------+ 10 rows in set (0.00 sec) Date : 2012-2-24 Fri 22:43:46 mysql> set wait_timeout=1; Query OK, 0 rows affected (0.00 sec) Date : 2012-2-24 Fri 22:43:52 mysql> set wait_timeout=1; ERROR 2006 (HY000): MySQL server has gone away No connection. Trying to reconnect... Connection id: 8 Current database: *** NONE *** Query OK, 0 rows affected (0.00 sec) Date : 2012-2-24 Fri 22:43:55 #可見即便在交互模式下真正起做用的也是wait_timeout而不是interactive_timeout
那爲何手冊上說在交互模式下使用的是interactive_timeout呢,緣由以下:函數
check_connection函數在創建鏈接初期,若是爲交互模式則將interactive_timeout值賦給wait_timeout,騙您誤覺得交互模式下等待超時爲interactive_timeout 代碼以下:測試
if (thd->client_capabilities & CLIENT_INTERACTIVE) thd->variables.net_wait_timeout=thd->variables.net_interactive_timeout;
參數含義:服務器關閉交互式鏈接前等待活動的秒數。交互式客戶端定義爲在mysql_real_connect()中使用CLIENT_INTERACTIVE選項的客戶端。
參數默認值:28800秒(8小時)
看到這兒若是您看累了,那下面您得提提神了,接下來的兩個參數纔是咱們遇到的最大的難題。 「The number of seconds to wait for a block to be written to a connection before aborting the write.」 等待將一個block發送給客戶端的超時,通常在網絡條件比較差的時,或者客戶端處理每一個block耗時比較長時,因爲net_write_timeout致使的鏈接中斷很容易發生。下面是一個模擬的例子:
mysql > set global max_allow_packet=1; #目的是讓結果集被分紅多個包傳輸給客戶端 mysql > set global net_write_timeout=1; #include #include #include main() { MYSQL *conn; MYSQL_RES *res; MYSQL_ROW row; char *server = "localhost"; char *user = "test"; char *password = ""; /* set me first */ char *database = "test"; conn = mysql_init(NULL); /* Connect to database */ if (!mysql_real_connect(conn, server, user, password, database, 0, NULL, 0)) { fprintf(stderr, "%s\n", mysql_error(conn)); exit(1); } /* send SQL query */ if (mysql_query(conn, "SELECT * from big_table;")) { fprintf(stderr, "%s\n", mysql_error(conn)); exit(1); } res = mysql_use_result(conn); #mysql_use_result不會一次將所有結果給都丟給客戶端內存 /* output table name */ printf("MySQL Tables in mysql database:\n"); sleep(7); #模擬網絡環境不穩定或客戶端處理耗時 while ((row = mysql_fetch_row(res)) != NULL){ printf("%s \n", row[0]); } /* close connection */ mysql_free_result(res); mysql_close(conn); }
「The number of seconds to wait fprintfor more data from a connection before aborting the read.」。Mysql讀數據的時的等待超時,可能的緣由可能爲網絡異常或客戶端or服務器端忙沒法及時發送或接收處理包。這裏我用的是iptables來模擬網絡異常,生成一個較大的數據以便於給我充足的時間在load data的過程當中去配置iptables規則。
mysql > set global max_allowed_packet=1073741824; mysql > set global net_read_timeout=1; mysql > create table test.test(a char(10)) engine=myisam; for((i=0;i<100000;i++));do echo "abcdefghij" >> data.txt;done mysql -uroot -h 127.0.0.1 -P 3306 --local-enable=1 --max-allowed-packet=1073741824 mysql > load data local infile 'load.txt' into table test; iptables -F /sbin/iptables -A INPUT -p tcp --dport 3306 -j DROP /sbin/iptables -A OUTPUT -p tcp --sport 3306 -j DROP iptables -L
執行完iptables命令後show processlist能夠看到load data的鏈接已經被中斷掉了,但由於這裏我選擇了myisam表,因此select count(*) from test;能夠看到數據仍是被插入了一部分。
「超時」的孿生兄弟「重試」,時間緣由這個我沒有進行實際的測試,手冊如是說,估且先信它一回。
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。
參考連接:
MySQL中的配置參數interactive_timeout和wait_timeout(可能致使過多sleep進程的兩個參數)