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