压测场景下的 TIME_WAIT 处理
1. 序
某專有云項目具備壓測場景,在Windows的壓測機上用 LoadRunner 進行業(yè)務(wù)的壓力測試,壓測運行一段時間后出現(xiàn)大量端口無法分配的報錯。
其實通過問題描述,以及 Windows的報錯信息基本確定是壓測機的問題。但可能原因較多,一直未能達成一致。所以,趁機分析了客戶端的壓測機成為壓測瓶頸的可能,除了CPU、網(wǎng)絡(luò)、 I/O 等機器性能參數(shù)外,仍需考慮網(wǎng)絡(luò)協(xié)議引入的資源短缺問題。
注:以下內(nèi)容的目的是理清TCP協(xié)議中比較模糊的內(nèi)容,對協(xié)議比較熟悉的可以忽略。
2. TIME_WAIT基礎(chǔ):RFC 793 TCP協(xié)議
眾所周知, TCP存在三次握手,四次揮手過程。其具體設(shè)計的目的,簡而言之,是為了在不穩(wěn)定的物理網(wǎng)絡(luò)環(huán)境中確保可靠的數(shù)據(jù)傳輸;因此,TCP在具體實現(xiàn)中加入了很多異常狀況的處理,整體協(xié)議就變得比較復雜。
要理解TCP協(xié)議,推薦閱讀 RFC 793,可參考文后鏈接了解詳情[1]。同時,也要理解“TCP state transition”狀態(tài)機,如下圖所示,可參考文后資料了解詳情[2]。
圖1. TCP狀態(tài)轉(zhuǎn)換圖
本文僅針對 TW 在TCP協(xié)議中的作用進行討論,不涉及整體協(xié)議的分析。四次揮手后的TIME_WAIT 狀態(tài),后續(xù)將以TW縮寫替代。
2.1 TW 作用
首先,主要作用是保證TCP連接關(guān)閉的可靠性。
考慮下在四次揮手過程中,如果主動關(guān)閉方發(fā)送的LAST_ACK丟失,那么被動關(guān)閉方會重傳FIN。此時,如果主動關(guān)閉方對應(yīng)的TCP Endpoint沒有進入TW狀態(tài)而是直接在內(nèi)核中清理了,根據(jù)協(xié)議,主動關(guān)閉方會認為自己沒有打開過這個端口,而以RST響應(yīng)被動關(guān)閉方重傳的FIN。最終該行為導致被動關(guān)閉方認為連接異常關(guān)閉,在業(yè)務(wù)上可能會收到異常報錯等情況。
其次,TW狀態(tài)同時也能避免相同的TCP端口收到在網(wǎng)絡(luò)上前一個連接的重復數(shù)據(jù)包。
理論上,數(shù)據(jù)包在網(wǎng)絡(luò)上過期時間對應(yīng)即MSL(Maximal Segment Lifetime),隨著操作系統(tǒng)的不斷發(fā)展,也有例外情況,這部分搜索PAWS應(yīng)該可以看到不少類似的文章說明。
再次,端口進入 TW 狀態(tài) 同時也避免了被操作系統(tǒng)快速重復使用的可能。
2.2 TW形成的原因
當一臺主機操作系統(tǒng)主動關(guān)閉TCP Endpoint(socket)時,該TCP Endpoint進入TW狀態(tài)。以Windows為例,Windows內(nèi)核會對 TCP Endpoint 數(shù)據(jù)結(jié)構(gòu)進行相應(yīng)清理,然后放入額外的 TW queue 中,設(shè)置2MSL 的定時器,等待定時器超時后調(diào)用對應(yīng)的釋放代碼。Linux上的實現(xiàn)也是類似。
目前較多的說法是"TCP連接"進入TW ,但我們可能需要理解 "連接" 其實是抽象的概念。實際上"連接"在邏輯上存在,因為客戶端和服務(wù)器端以及中間可能涉及的4層設(shè)備同時為一次傳輸創(chuàng)建了關(guān)聯(lián)的TCP資源(Endpoint,或者 Session)。準確理解TW狀態(tài),即TCP EndpointTW進入TW狀態(tài)。
2.3 小結(jié)
TW 是為了保證 TCP 連接正常終止(避免端口被快速復用),也是為了保證網(wǎng)絡(luò)中迷失的數(shù)據(jù)包正常過期(防止前一個連接的數(shù)據(jù)包被錯誤的接收)。
TW暗殺術(shù),可參考文后資料了解詳情[3]。
3. 概念澄清
歡迎討論
幾個可能比較模糊的地方,明確如下:
該情況在邏輯上是成立的,可參考文后資料了解詳情[4]。
針對前面的 TCP Endpoint 這個詞語,可能很多人不太了解,這邊也簡單說明下:
在Windows 2008 R2之前,socket是用戶態(tài)(user mode) 的概念,大多數(shù)Windows socket應(yīng)用程序基本都基于Winsock開發(fā),由中間層AFD.sys 驅(qū)動翻譯成內(nèi)核 tcpip.sys 協(xié)議棧驅(qū)動 所能接受的TCP Endpoint數(shù)據(jù)結(jié)構(gòu)。在2008 R2之后,微軟為了方便內(nèi)核的網(wǎng)絡(luò)編程,在Windows Kernel中提供WSK,即Winsock在內(nèi)核的實現(xiàn)。文中提到的TCP Endpoint是在Windows內(nèi)核中由TCPIP.sys驅(qū)動文件實現(xiàn)的TCP數(shù)據(jù)結(jié)構(gòu),也對應(yīng)Linux上的socket。該文簡單以 Endpoint 代指內(nèi)核的"socket"。
4. TW 優(yōu)化手段
對于Linux,優(yōu)化手段已經(jīng)進行了很多討論了,以Centos為例,
針對客戶端,連接請求發(fā)起方。
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tw_reuse = 1
針對服務(wù)器端,連接請求接收方
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tw_recycle = 1
注:tcp_tw_recycle的啟用會帶來一些 side effect,具體在NAT地址轉(zhuǎn)換場景下,容易發(fā)生連接異常問題。
可參考文后資料了解詳情[4]。
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.ip_local_port_range = 5000 65535
針對Windows ,資料較少,這邊借之前的工作經(jīng)驗,總結(jié)如下:
端口范圍:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
MaxUserPort = 0n65534
TW 超時時間:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
TcpTimedWaitDelay = 0n30
端口范圍:
netsh int ipv4 set dynamicport tcp start=1025 num=64511
TW 超時時間:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
TcpTimedWaitDelay = 0n30
Windows Server 2012 and earlier: 30-300 (decimal)
Windows 8 and earlier: 30-300 (decimal)
Windows Server 2012 R2 and later: 2-300 (decimal)
Windows 8.1 and later: 2-300 (decimal)
注:
- 任何涉及注冊表的修改,只有重啟機器才會生效。
- 與 Linux不同,Windows 沒有快速回收機制,不存在快速回收 TW 的可能,只能等待2MSL過期(即TcpTimedWaitDelay)。
- Windows唯一能快速回收TW狀態(tài)的Endpoint 的情況:
新連接請求的SEQ序列號>TW狀態(tài)的Endpoint記錄的SEQ序列號。
此時,內(nèi)核會認為該 SYN 請求合法。 這里,這個TW 狀態(tài)的 TCP Endpoint 一定是在服務(wù)端(通過socket accept 打開的 服務(wù)端口)。(為了這個能力,Windows 的 RFC 1323 選項必須打開,內(nèi)容可以自行搜索。)
5. 壓測客戶端無法分配端口的原因分析
端口無法分配有兩種可能:
- 完全隨機的動態(tài)端口請求,報錯端口分配異常,基本是操作系統(tǒng)沒有可用端口。
- 指定端口的綁定申請報錯端口分配異常,可能存在端口使用沖突問題。
針對第一種情況,首先需要通過 netstat -ano 進行快速檢查,分析是否存在端口占滿的情況,以及占滿端口的TCP Endpoint狀態(tài)。針對不同的狀態(tài),考慮不同的方案。
比如,極端情況下,沒有任何異常的服務(wù)器上,端口分配失敗問題,可參考文后資料了解詳情[5]。
以Windows操作系統(tǒng)TW狀態(tài)Endpoint占滿可用端口場景為例(在Linux上發(fā)生的可能性較低),分析問題前需要大概了解 Windows 上端口分配原理。
- Windows和Linux在動態(tài)分配端口的機制上有很大的不同。
- Linux以粗淺的理解應(yīng)該是針對五元組的分配,即可能存在相同的動態(tài)端口訪問不同服務(wù)器的服務(wù)端口。
- Windows的動態(tài)端口分配實現(xiàn)基于Bitmap查找,無論訪問哪里,動態(tài)端口的池子最大為 1025 – 65536,即64511個。
- 考慮到最短30秒的 TW 超時時間,如果按照 64511/29 = 2225 ports/s 的速度去創(chuàng)建端口,那么很可能在30秒后持續(xù)發(fā)生端口無法分配的問題。
- 這還是在連接處理比較快速的情況下,如果連接建立后不關(guān)閉,或者關(guān)閉時間比較久,創(chuàng)建端口的速度仍需持續(xù)下降來規(guī)避端口問題。
理解了 TW 的形成原因,相應(yīng)的解決方案也就比較清楚了。
a) 不讓該機器主動關(guān)閉連接,而讓對方主動關(guān)閉。這樣,該主機進入被動關(guān)閉進程,在應(yīng)用關(guān)閉TCP Endpoint之后,可直接釋放端口資源。
一些協(xié)議本身就有控制是否保持連接或者請求對方關(guān)閉連接的行為或者參數(shù),在考慮這類問題的時候,可以適當進行利用。比如 HTTP 的長短連接,可參考文后資料了解詳情[4]。
b) 通過TCP Reset強制釋放端口。TCP Reset可以由任何一方發(fā)出,無論是發(fā)送方還是接收方,在看到TCP Reset之后會立刻將對應(yīng)TCP Endpoint拆除。
這里,可設(shè)置 socket 的 SO_LINGER選項,比如配置Nginx,可參考文后官方文檔了解詳情[6]。
圖2:Nginx Lingering配置參考說明
針對壓測工具本身,官方網(wǎng)站上也有類似 ABRUPT 選項,可參考文后官方文檔了解詳情[7]。
圖3:LoadRunner ABRUPT配置選項說明
參考文檔
[1] RFC 793:https://tools.ietf.org/html/rfc793
[2] IBM TCP state transition:https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.halu101/constatus.htm
[3] TIME-WAIT Assassination Hazards in TCP:https://tools.ietf.org/html/rfc1337
[4] Tengine健康檢查引發(fā)大量TIME_WAIT堆積:https://developer.aliyun.com/article/781244
[5] CloudMonitor 引發(fā)的網(wǎng)絡(luò)問題排查一則:https://developer.aliyun.com/article/682535
[6] 配置Nginx:http://nginx.org/en/docs/http/ngx_http_core_module.html#lingering_close
[7] ABRUPT選項:https://admhelp.microfocus.com/lr/en/2020_SP2-SP3/help/function_reference/Content/FuncRef/web/lrFR_web_set_sockets_option.htm?Highlight=web_set_socket_option#Shutdown
我們是阿里云智能全球技術(shù)服務(wù)-SRE團隊,我們致力成為一個以技術(shù)為基礎(chǔ)、面向服務(wù)、保障業(yè)務(wù)系統(tǒng)高可用的工程師團隊;提供專業(yè)、體系化的SRE服務(wù),幫助廣大客戶更好地使用云、基于云構(gòu)建更加穩(wěn)定可靠的業(yè)務(wù)系統(tǒng),提升業(yè)務(wù)穩(wěn)定性。我們期望能夠分享更多幫助企業(yè)客戶上云、用好云,讓客戶云上業(yè)務(wù)運行更加穩(wěn)定可靠的技術(shù)。
原文鏈接:https://developer.aliyun.com/article/781757?
版權(quán)聲明:本文內(nèi)容由阿里云實名注冊用戶自發(fā)貢獻,版權(quán)歸原作者所有,阿里云開發(fā)者社區(qū)不擁有其著作權(quán),亦不承擔相應(yīng)法律責任。具體規(guī)則請查看《阿里云開發(fā)者社區(qū)用戶服務(wù)協(xié)議》和《阿里云開發(fā)者社區(qū)知識產(chǎn)權(quán)保護指引》。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,填寫侵權(quán)投訴表單進行舉報,一經(jīng)查實,本社區(qū)將立刻刪除涉嫌侵權(quán)內(nèi)容。總結(jié)
以上是生活随笔為你收集整理的压测场景下的 TIME_WAIT 处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 服务网格的最佳实践
- 下一篇: E百科 | 基于MEC的边缘AI服务