MySQL的各種網絡IO超時的用法和實現


 

2016-04-06 趙偉 數據庫開發者

 

客戶端C API

在C API中調用mysql_options()來設置mysql_init() 所創建的連接對象的屬性,使用這三個選項可以設置連接超時和讀寫超時,單位都是秒。讀寫超時達到后C API的查詢發送和結果獲取函數會返回超時錯誤。

 

MYSQL_OPT_CONNECT_TIMEOUT

MYSQL_OPT_READ_TIMEOUT

MYSQL_OPT_WRITE_TIMEOUT

 

也可以使用配置文件來設置連接超時和交互超時:

connect-timeout=seconds

interactive-timeout=seconds

當客戶端API在向mysql server發起連接connect-timeout秒后沒有收到mysql server的相應那么認為連接失敗。

interactive-timeout是用於這個客戶端連接的交互超時。交互超時用於在交互界面程序(比如mysql這個連接客戶端程序)中設置server的會話超時時間,來賦值給wait_timeout會話變量,它通常比較大,因為使用這個交互界面的通常是人類在手動操作,而不是程序執行和發送指令。mysql server默認使用會話變量@@wait_timeout 作為會話的超時,除非在mysql_real_connect中使用CLIENT_INTERACTIVE標志來標識這個連接是用於交互操作,此時如果客戶端有interactive-timeout就使用它來作為本會話的會話超時,否則使用服務器端的interactive-timeout作為會話超時設置給wait_timeout。

MySQL Server內部

從下圖中可以看出,服務器端關於超時的變量有很多,這里去掉了我們的TDSQL特有的非標准的MySQL/MariaDB的幾個超時值。其中的connect_timeout, net_read_timeout, net_write_timeout,slave_net_timeout, interactive_timeout和wait_timeout與網絡IO有關。

 

其中,connect_timeout 被用於在用戶登錄期間,也就是建立數據庫連接期間,作為mysql server端的網絡讀寫超時。這與文檔上面的說法並不相同,但是代碼中確實是這樣子的。

 

net_read_timeout 和net_write_timeout是數據庫會話創建好之后mysql server端使用的讀寫超時。如果讀取或者寫入操作在等待了達到超時后服務器認為客戶端連接斷開,執行錯誤處理。

 

而slave_net_timeout是slave的io線程使用客戶端C API連接master時候,調用mysql_options()來設置MYSQL_OPT_CONNECT_TIMEOUT,MYSQL_OPT_READ_TIMEOUT,MYSQL_OPT_WRITE_TIMEOUT這三個超時選項使用的值。IO線程連接master使用的都是標准的客戶端C API代碼和通信協議。

 

最后,wait_timeout是mysqld server的默認的會話超時,如果一個數據庫連接(會話)在這么長時間之后沒有任何讀寫動作,那么這個連接被關閉。interactive_timeout是默認的交互式連接的會話超時,會設置給wait_timeout,如果客戶端有自定義的值,那么那個值會被優先使用來設置給wait_timeout。

 

所有這些超時可以分為連接超時,讀寫超時和會話超時三類,下面就講一下這些超時機制是如何實現的。

超時的實現方法

在Linux的connect(), recv, send, read(), write()等系統調用中,並不可以簡單地阻塞等待一段指定時間后再返回錯誤,而是要么把文件句柄設置為非阻塞的(使用fcntl()和O_NONBLOCK標志,或者對於recv/send()可以每次調用使用MSG_DONTWAIT)並且立刻返回,要么一直阻塞等待。所以,要實現超時還是要一點小技巧的。另外,MySQL中網絡IO的代碼無論是客戶端C API的網絡IO功能還是服務器內部使用的網絡通信功能,都是同一份代碼實現,因此下文不需要區分客戶端和服務器端。

連接超時

相關函數:vio_socket_connect(),vio_io_wait()

 

首先,如果有連接超時時間的話,就設置socket fd為非阻塞的,然后調用標准的socket函數connect()來發起連接,這個函數會立即返回-1並且設置errno為 EINPROGRESS或者EALREADY。然后,調用vio_io_wait()來使用poll()來阻塞等待這個連接可以寫入,使用連接超時值作為poll()的超時參數。這樣,在等待超時后就認為連接失敗,否則連接就成功了。這里並沒有使用網絡協議自己的連接超時,因為那樣的話無法在不影響其他進程的情況下隨時靈活更改這個超時時間。

 

讀寫超時

相關函數:vio_read(), vio_write(), vio_socket_io_wait()

 

首先,調用標准的recv()/send()系統調用來讀取或者寫入,如果有讀寫超時時間的話,就使用MSG_DONTWAIT作為最后一個flags參數,這樣如果沒有數據可以讀取或者無法寫入(比如網絡擁塞)這個函數會立刻返回SOCKET_EAGAIN 或者SOCKET_EWOULDBLOCK,於是,調用vio_socket_io_wait()來阻塞等待這個socket fd可以讀或者寫,這個函數主要是調用了poll(),並且用讀寫超時值作為poll()的等待超時時間。

 

會話超時

這里的會話(Session)其實就是數據庫連接,在mysql內部對應於THD類。會話超時是Mysql server端才有的機制,在客戶端沒有。實現方法是:Mysql server內部線程定期檢查所有THD會話對象的狀態,將會話超時的THD對象銷毀。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM