天天看點

故障分析 | MySQL Server 端為什麼有大量的TCP TIME_WAIT ?

作者:愛可生

作者:李鵬博

愛可生 DBA 團隊成員,主要負責 MySQL 故障處理和 SQL 稽核優化。對技術執着,為客戶負責。

本文來源:原創投稿

*愛可生開源社群出品,原創内容未經授權不得随意使用,轉載請聯系小編并注明來源。

最近客戶的一台 MySQL Server 告警處于 TCP TIME_WAIT 狀态的連接配接過多,通過檢視相關監控發現 TCP Connections 中處于 TIME_WAIT 狀态的連接配接一直在 3000~4000 ,如圖:

故障分析 | MySQL Server 端為什麼有大量的TCP TIME_WAIT ?

在 OS 上檢視 TCP 處于 TIME_WAIT 狀态的連接配接:

故障分析 | MySQL Server 端為什麼有大量的TCP TIME_WAIT ?

(其中161伺服器是本地的 MySQL Server ,4125是資料庫端口,234是遠端應用伺服器)

可以看到所有處于 TIME_WAIT 狀态的 TCP 連接配接都是應用伺服器234到本地161的資料庫連接配接,此時心中有一個疑問:隻有主動關閉 TCP 連接配接的一端才會存在 TIME_WAIT 狀态,主觀的想法就是大量的 TIME_WAIT 應該位于應用伺服器一端,哪為何 MySQL Server 這一端有這麼多處于 TIME_WAIT 狀态的 TCP 連接配接?難道是有大量由于 wait_timeout 逾時的連接配接,是以 MySQL Server 這一端主動關閉了連接配接,還是由于網絡異常或用戶端異常關閉,導緻 MySQL Server 一端主動關閉了連接配接,但是通過觀察 MySQL Connections 相關監控發現連接配接數量一直都是比較少的:

故障分析 | MySQL Server 端為什麼有大量的TCP TIME_WAIT ?

是以就不是由于大量的連接配接因為 wait_timeout 逾時而造成的 MySQL Server 一端主動關閉了連接配接。

通過檢視 mysqld error log 裡面也沒有太多關于“Aborted connection”或“Got an error reading communication packets”,是以也不是由于網絡異常或用戶端異常關閉導緻的 MySQL Server 一端主動關閉了連接配接。

此時就想從系統角度入手看能不能進行相關調整,之後将 net.ipv4.tcp_tw_recycle 系統參數從0調整為了1,然後觀察 TCP Connections 相關監控發現效果非常明顯,TIME_WAIT 狀态的 TCP 連接配接瞬間就降下去了:

故障分析 | MySQL Server 端為什麼有大量的TCP TIME_WAIT ?

但是查詢相關資料發現tcp_tw_recycle這個參數是有坑的:https://linux.die.net/man/7/tcp

故障分析 | MySQL Server 端為什麼有大量的TCP TIME_WAIT ?

是以雖然效果很明顯,但是為了穩妥起見,還是将 net.ipv4.tcp_tw_recycle 參數改回了0。

這時就隻能換一個思路:通過抓包看看資料庫伺服器和應用伺服器到底是如何通信的,由于沒有權限登入應用伺服器,就隻能在161資料庫伺服器上通過 tcpdump 單向抓包并使用 Wireshark 工具進行分析。

通過分析發現在抓取的68000多個包中存在大量的FIN包和SYN包,由此說明應用伺服器存在大量的短連接配接,一直在連接配接資料庫,短時間的查詢之後又斷開連接配接,并不斷反複:

故障分析 | MySQL Server 端為什麼有大量的TCP TIME_WAIT ?

但是這依舊不能解釋為什麼 MySQL Server 一端存在大量處于 TIME_WAIT 狀态的 TCP 連接配接。

繼續分析網絡包之後發現當 Client 請求退出之後,Client 和 Server 之間的 TCP 連接配接有兩種斷開方式:

第一種:

234應用伺服器發出退出請求,161資料庫伺服器回複“ACK”包,然後由234應用伺服器主動斷開連接配接。

故障分析 | MySQL Server 端為什麼有大量的TCP TIME_WAIT ?

第二種:

234應用伺服器發出退出請求,161資料庫伺服器主動斷開與234應用伺服器的連接配接。

故障分析 | MySQL Server 端為什麼有大量的TCP TIME_WAIT ?

此時我們就可以得出結論:在 MySQL 退出會話時,Client 與 MySQL Server之 間,TCP 連接配接的斷開有可能是由 Client 發起的,也有可能是由 Server 發起的,而并不是我們主觀認為的都是由 Client 發起的,是以當 Client 與 MySQL Server 之間存在大量的短連接配接時,MySQL Server 的 OS 上就可能會存在大量處于 TIME_WAIT 狀态的 TCP 連接配接,而解決方法就是由應用側将大量的短連接配接由少量的長連接配接代替。

在 MySQL Internals Manual 上也有相關 Client 退出會話時 MySQL Server 的動作說明:https://dev.mysql.com/doc/internals/en/com-quit.html

故障分析 | MySQL Server 端為什麼有大量的TCP TIME_WAIT ?

這也剛好印證了通過抓包看到的現象。

繼續閱讀