絡(luò)診斷到性能優(yōu)化實戰(zhàn))
1. 從抓包到診斷為什么我們需要關(guān)注TCP異常報文如果你做過網(wǎng)絡(luò)運(yùn)維或者后端開發(fā)肯定遇到過這種情況服務(wù)響應(yīng)時快時慢接口偶爾超時日志里風(fēng)平浪靜但用戶那邊就是卡住了。這時候光看應(yīng)用日志和監(jiān)控大盤往往找不到根因。問題的答案大概率藏在網(wǎng)絡(luò)層的數(shù)據(jù)流里。而Wireshark就是我們窺探這片“黑暗森林”的夜視儀。TCP協(xié)議作為互聯(lián)網(wǎng)的基石以其可靠性著稱。但“可靠”不等于“一帆風(fēng)順”。丟包、亂序、擁塞、窗口變化……這些底層事件都會以特定形態(tài)的TCP報文在網(wǎng)絡(luò)中穿梭。一個健康的TCP流其報文序列就像一首節(jié)奏穩(wěn)定的交響樂而一旦出現(xiàn)異常報文就如同樂章中出現(xiàn)了刺耳的音符或長時間的停頓。這些“異常音符”——比如重復(fù)的ACK、重傳的報文段、零窗口通告、連接重置——并非錯誤本身而是TCP協(xié)議棧在努力適應(yīng)或修復(fù)網(wǎng)絡(luò)問題時發(fā)出的“信號彈”。因此分析Wireshark捕獲到的TCP異常報文其核心價值不在于“看熱鬧”而在于“看門道”。它讓我們能夠穿透表象定位根因?qū)?yīng)用層的“慢”或“超時”精準(zhǔn)定位到網(wǎng)絡(luò)層的丟包、對端處理能力不足或是中間設(shè)備策略限制。量化評估網(wǎng)絡(luò)質(zhì)量通過統(tǒng)計重傳率、亂序率等指標(biāo)客觀評估網(wǎng)絡(luò)鏈路的穩(wěn)定性。驗證架構(gòu)與配置驗證TCP參數(shù)如tcp_tw_recycle 雖然現(xiàn)在已廢棄、負(fù)載均衡策略、防火墻規(guī)則是否按預(yù)期工作。簡單說掌握TCP異常報文分析就是給你的故障排查工具箱里增加了一把能直接看到“血管”網(wǎng)絡(luò)流狀況的手術(shù)刀。下面我們就結(jié)合具體報文逐一拆解這些常見“信號彈”的含義、成因和應(yīng)對思路。2. 重傳與重復(fù)ACK網(wǎng)絡(luò)丟包的經(jīng)典信號這是Wireshark分析中最常見、也最需要仔細(xì)甄別的一類異常。很多人一看到TCP Retransmission或TCP Dup ACK就認(rèn)為是網(wǎng)絡(luò)問題這其實有點(diǎn)武斷。我們需要像偵探一樣結(jié)合上下文來判斷。2.1 TCP快速重傳與重復(fù)ACK的協(xié)同機(jī)制首先得理解標(biāo)準(zhǔn)流程。接收方每收到一個按序的報文段會回復(fù)一個ACK確認(rèn)號是期望收到的下一個字節(jié)序號。假設(shè)發(fā)送方發(fā)送了Seq 1-1000, 1001-2000, 2001-3000三個包。正常情況收到1-1000回ACK 1001收到1001-2000回ACK 2001收到2001-3000回ACK 3001。出現(xiàn)丟包1-1000和2001-3000到了但1001-2000丟了。接收方此時會收到1-1000回ACK 1001。收到2001-3000這是一個亂序包因為期望的是1001。接收方無法確認(rèn)2001-3000因為它不連續(xù)。此時它會立即再次發(fā)送ACK 1001這就是第一個TCP Dup ACK。這個重復(fù)ACK的意思是“我仍然在等序號1001開始的數(shù)據(jù)但我收到了一個更后面的包你快看看是不是1001-2000丟了”如果后續(xù)又收到了3001-4000還是亂序它會繼續(xù)回復(fù)ACK 1001產(chǎn)生第二個TCP Dup ACK。按照TCP標(biāo)準(zhǔn)當(dāng)發(fā)送方連續(xù)收到3個或以上對同一個序號的重復(fù)ACK時它就高度懷疑這個序號對應(yīng)的數(shù)據(jù)包丟失了于是不等超時計時器到期立刻重傳疑似丟失的包Seq 1001-2000。這就是“快速重傳”機(jī)制。在Wireshark中這個重傳的包會被標(biāo)記為TCP Retransmission。Wireshark中的關(guān)鍵觀察點(diǎn)找模式觀察是否先出現(xiàn)3個或以上連續(xù)的TCP Dup ACK緊接著出現(xiàn)一個TCP Retransmission。這是典型的快速重傳觸發(fā)場景指向單包丟失??葱蛄刑柎_認(rèn)TCP Dup ACK的確認(rèn)號Acknowledgment number是否停滯不前。比如一直ACK 1001說明接收方卡在1001這個位置。計算頻率如果重傳后流很快恢復(fù)正??赡苤皇桥及l(fā)的鏈路抖動。如果重傳頻繁發(fā)生甚至出現(xiàn)“重傳的重傳”那鏈路質(zhì)量可能堪憂。注意Wireshark的TCP Dup ACK和Retransmission標(biāo)記是基于其內(nèi)置的啟發(fā)式算法。有時因為抓包位置如在客戶端抓包但包在服務(wù)端出口丟失或時間戳精度問題標(biāo)記可能不絕對準(zhǔn)確需要結(jié)合Seq和Ack號手動驗證。2.2 超時重傳更嚴(yán)重的網(wǎng)絡(luò)問題指示如果丟失的數(shù)據(jù)包后面沒有足夠多的新數(shù)據(jù)包來觸發(fā)重復(fù)ACK例如丟失的是窗口中的最后一個包或者網(wǎng)絡(luò)亂序非常嚴(yán)重快速重傳機(jī)制就無法生效。這時發(fā)送方只能依賴“超時重傳”機(jī)制。發(fā)送方為每個已發(fā)送未確認(rèn)的報文段維護(hù)一個重傳計時器RTO。如果超過RTO時間仍未收到該報文段的ACK就會進(jìn)行超時重傳。在Wireshark中這同樣被標(biāo)記為TCP Retransmission但其上下文沒有前置的多個TCP Dup ACK。超時重傳的嚴(yán)重性更高因為RTO時間通常較長基于RTT動態(tài)計算在延遲高的網(wǎng)絡(luò)中可能達(dá)到數(shù)秒。一次超時重傳意味著應(yīng)用至少延遲了RTO時長。觸發(fā)擁塞控制激進(jìn)回退TCP會認(rèn)為網(wǎng)絡(luò)發(fā)生了嚴(yán)重?fù)砣粌H重傳丟失包還會將擁塞窗口cwnd大幅減小例如置為1個MSS并進(jìn)入慢啟動狀態(tài)。這對吞吐量是毀滅性打擊。排查思路鏈路質(zhì)量檢查客戶端、服務(wù)器、中間網(wǎng)絡(luò)設(shè)備的鏈路是否存在物理不穩(wěn)定、CRC錯誤激增等情況。ping配合-t和-l加大包長測試可能暴露問題。路徑MTU問題如果報文長度超過路徑上某個節(jié)點(diǎn)的MTU且又沒有正確設(shè)置DF位或啟用PMTUD可能導(dǎo)致分包異常或丟包。觀察重傳的包是否都是大尺寸報文。對端主機(jī)處理能力服務(wù)器負(fù)載過高TCP內(nèi)核協(xié)議棧或應(yīng)用程序來不及處理導(dǎo)致緩沖區(qū)滿也可能表現(xiàn)為丟包。需結(jié)合服務(wù)器監(jiān)控CPU、軟中斷、netstat -s中的TCP buffer errors判斷。2.3 偽重傳與亂序不要冤枉網(wǎng)絡(luò)不是所有被Wireshark標(biāo)記為重傳的包都是真正的重傳。常見兩種“冤案”偽重傳Spurious Retransmission場景網(wǎng)絡(luò)沒有丟包但ACK在回程路徑上延遲了導(dǎo)致發(fā)送方誤判超時并重傳。隨后延遲的ACK和針對重傳包的ACK都到達(dá)了。Wireshark特征你會看到兩個Seq號相同、載荷相同的包并且兩個包都收到了ACK。真正的重傳原始丟失包是不會被ACK的。影響造成不必要的帶寬浪費(fèi)并可能錯誤觸發(fā)擁塞控制。Linux內(nèi)核的TCP timestamp和SACK選項有助于緩解此問題。網(wǎng)絡(luò)亂序Out-of-Order場景數(shù)據(jù)包在網(wǎng)絡(luò)中走了不同路徑導(dǎo)致后發(fā)的包先到。Wireshark會標(biāo)記為TCP Out-of-Order。與丟包的區(qū)別亂序會導(dǎo)致TCP Dup ACK產(chǎn)生因為收到了更高序列號的包但通常不會達(dá)到3個以上因為亂序的包很快會到達(dá)然后接收方會發(fā)出新的累積ACK。如果亂序差距很大也可能觸發(fā)快速重傳造成“虛驚一場”。排查在數(shù)據(jù)中心內(nèi)部多路徑ECMP負(fù)載均衡策略配置不當(dāng)是常見原因。在公網(wǎng)屬于正常現(xiàn)象但頻繁嚴(yán)重亂序可能影響性能。實操心得面對重傳告警第一步不是急著找運(yùn)維而是先在Wireshark里用過濾表達(dá)式tcp.analysis.retransmission篩選出所有重傳包然后逐個展開查看其前后的報文序列結(jié)合時間戳和ACK號判斷是快速重傳、超時重傳還是偽重傳。這個分析過程本身就能排除掉至少一半的非網(wǎng)絡(luò)問題。3. 零窗口與窗口更新接收端壓力的直接體現(xiàn)如果說重傳是發(fā)送路徑上的問題那么零窗口問題就是接收路徑上的瓶頸。它直觀地告訴我們接收方“吃不動了”。3.1 零窗口通告的原理與抓包識別TCP的滑動窗口機(jī)制中接收方會在每個ACK包中通告自己的接收窗口大小Win字段告訴發(fā)送方“我還能收多少字節(jié)”。這個窗口大小受制于接收方的套接字緩沖區(qū)剩余空間。當(dāng)接收方應(yīng)用層讀取數(shù)據(jù)過慢導(dǎo)致內(nèi)核接收緩沖區(qū)被填滿時其通告的窗口大小會逐漸減小直至變?yōu)?。此時接收方會發(fā)出一個窗口大小為0的ACK包即“零窗口通告”。在Wireshark中這個包的信息欄通常會明確提示TCP ZeroWindow。發(fā)送方收到零窗口通告后必須停止發(fā)送數(shù)據(jù)除了極少數(shù)例外如保活探測并啟動一個“持續(xù)計時器”。定時例如每5-10秒向接收方發(fā)送一個1字節(jié)的“零窗口探測包”以查詢窗口是否已重新打開。Wireshark分析要點(diǎn)確認(rèn)零窗口源頭找到第一個TCP ZeroWindow包查看其源IP那就是“吃不動”的主機(jī)。觀察持續(xù)時間查看從第一個零窗口通告到收到第一個非零窗口的TCP Window Update之間的時間差。這個時間就是數(shù)據(jù)流被阻塞的時長。在IOPS或統(tǒng)計圖表中這通常表現(xiàn)為一條漫長的水平線。檢查探測機(jī)制觀察發(fā)送方是否在定期發(fā)送小包Seq號不變或微小增長Len1進(jìn)行探測。這證明TCP協(xié)議在正常工作。3.2 零窗口問題的根本原因排查接收方窗口為零根本原因是應(yīng)用層消費(fèi)速度跟不上網(wǎng)絡(luò)層接收速度。具體可能包括應(yīng)用邏輯阻塞接收方應(yīng)用程序在處理單個請求時耗時過長如復(fù)雜的數(shù)據(jù)庫查詢、同步IO操作導(dǎo)致無法及時從Socket緩沖區(qū)讀取數(shù)據(jù)。緩沖區(qū)設(shè)置過小操作系統(tǒng)或應(yīng)用設(shè)置的Socket接收緩沖區(qū)SO_RCVBUF太小無法容納突發(fā)的數(shù)據(jù)流。特別是在高帶寬、高延遲長肥網(wǎng)絡(luò)的環(huán)境中需要更大的緩沖區(qū)來保持管道充盈。接收端CPU或IO瓶頸服務(wù)器整體負(fù)載過高導(dǎo)致即使應(yīng)用邏輯簡單也無力及時處理網(wǎng)絡(luò)數(shù)據(jù)。背壓傳導(dǎo)在微服務(wù)調(diào)用鏈中下游服務(wù)阻塞會導(dǎo)致背壓向上游傳導(dǎo)最終可能使最源頭的客戶端接收窗口變?yōu)榱?。排查與優(yōu)化定位進(jìn)程在零窗口期間在接收方主機(jī)上使用ss -tnp命令找到對應(yīng)連接查看其接收隊列Recv-Q是否積壓并確認(rèn)占用該Socket的進(jìn)程。檢查緩沖區(qū)大小通過sysctl net.ipv4.tcp_rmem查看系統(tǒng)默認(rèn)值或通過ss -nt查看具體連接的skmem信息。考慮適當(dāng)增大net.ipv4.tcp_rmem的max值或在應(yīng)用中設(shè)置更大的SO_RCVBUF。優(yōu)化應(yīng)用這是治本之策。檢查接收方應(yīng)用的性能是否存在同步阻塞、是否可以考慮異步處理、是否可以進(jìn)行批處理以提高消費(fèi)效率。3.3 窗口更新與窗口縮放當(dāng)接收方應(yīng)用讀取數(shù)據(jù)騰出緩沖區(qū)空間后它會發(fā)送一個TCP Window Update包通告新的、更大的窗口大小讓發(fā)送方恢復(fù)數(shù)據(jù)傳輸。這里有一個常見陷阱TCP頭部中的Win字段只有16位最大只能表示65535字節(jié)64KB。在現(xiàn)代高速網(wǎng)絡(luò)中這遠(yuǎn)遠(yuǎn)不夠。因此TCP通過Window Scale選項在握手階段協(xié)商一個縮放因子Scale Factor。實際窗口大小 通告窗口值 縮放因子。Wireshark會幫我們完成這個計算。在包詳情中展開TCP層如果存在Window scale factor那么Wireshark顯示在Info列中的窗口大小如win 65535可能是縮放后的值或者它會直接顯示計算后的真實窗口值如Calculated window size: 4194240。分析時一定要以Wireshark計算或標(biāo)注的真實窗口為準(zhǔn)否則會嚴(yán)重誤判。注意某些中間設(shè)備如老舊防火墻或NAT設(shè)備可能會錯誤地處理或剝離TCP選項包括Window Scale導(dǎo)致兩端協(xié)商的縮放因子失效進(jìn)而引發(fā)窗口大小相關(guān)性能問題。如果在高速傳輸中觀察到窗口值始終很小且不變需要考慮這種可能性。4. 連接重置與標(biāo)志位異常會話的意外終結(jié)這類異常往往意味著連接被強(qiáng)制、非正常地終止需要重點(diǎn)關(guān)注。4.1 連接重置RST的多種含義一個帶有RST標(biāo)志的TCP包就像一通突然掛斷的電話。它可能由多種原因產(chǎn)生對端端口未監(jiān)聽客戶端嘗試連接服務(wù)器一個未開放的端口服務(wù)器內(nèi)核直接回復(fù)RST。這是最常見的“Connection refused”錯誤根源。異常關(guān)閉應(yīng)用在存在未讀數(shù)據(jù)或未發(fā)送數(shù)據(jù)的情況下直接調(diào)用close()或進(jìn)程崩潰內(nèi)核會發(fā)送RST來清空連接狀態(tài)而不是走正常的四次揮手。收到非法報文例如收到一個不屬于任何現(xiàn)有連接的報文序列號完全不對協(xié)議??赡軙訰ST響應(yīng)。這可能是網(wǎng)絡(luò)掃描或攻擊的跡象。中間設(shè)備干預(yù)防火墻、負(fù)載均衡器或入侵檢測系統(tǒng)基于安全策略主動發(fā)送RST斷開連接。半開連接清理一端已經(jīng)關(guān)閉或崩潰另一端仍認(rèn)為連接存在并發(fā)送數(shù)據(jù)存活的一方會回復(fù)RST。Wireshark分析RST看時機(jī)是在握手階段、數(shù)據(jù)傳輸中還是空閑一段時間后握手階段的RST通常指向服務(wù)未就緒傳輸中的RST可能是應(yīng)用異??臻e后的RST可能是防火墻會話超時??捶较蚴钦l發(fā)的RST客戶端還是服務(wù)端這有助于定位問題發(fā)起方。結(jié)合載荷RST包有時會攜帶最后的數(shù)據(jù)如果是因為異常關(guān)閉這些數(shù)據(jù)可能包含錯誤信息。使用過濾tcp.flags.reset 1可以快速過濾所有RST包。4.2 其他標(biāo)志位異常SYN 重傳客戶端發(fā)送SYN后未收到SYN-ACK會重傳SYN。這通常意味著服務(wù)器端口確實未監(jiān)聽最終會收到RST或超時。服務(wù)器SYN-ACK被中間網(wǎng)絡(luò)丟棄。服務(wù)器過于繁忙SYN隊列net.ipv4.tcp_max_syn_backlog已滿。客戶端發(fā)出的SYN包本身就在網(wǎng)絡(luò)中丟失。FIN 交換不完整正常四次揮手應(yīng)有兩對FIN-ACK。如果只看到單個FIN可能是另一端應(yīng)用崩潰或強(qiáng)制殺進(jìn)程導(dǎo)致連接變?yōu)椤鞍腙P(guān)閉”狀態(tài)最終由?;顧C(jī)制或超時清理。同時打開/同時關(guān)閉非常罕見的場景兩端幾乎同時發(fā)起SYN或FIN會產(chǎn)生特殊的報文序列Wireshark能正常解析通常無需處理。排查RST的實戰(zhàn)步驟確認(rèn)服務(wù)狀態(tài)如果是連接被拒首先檢查對端服務(wù)進(jìn)程是否存活端口是否監(jiān)聽 (netstat -tlnp)。檢查應(yīng)用日志在RST發(fā)生的時間點(diǎn)檢查兩端應(yīng)用程序的日志看是否有異常錯誤、主動關(guān)閉連接或未處理的信號。審查防火墻/安全策略檢查服務(wù)器本地防火墻iptables, firewalld以及網(wǎng)絡(luò)路徑上的安全設(shè)備規(guī)則是否有針對特定端口、IP或流量的重置規(guī)則。檢查系統(tǒng)參數(shù)對于SYN被拒絕檢查net.ipv4.tcp_max_syn_backlog和net.core.somaxconn參數(shù)是否過小。對于TIME_WAIT過多導(dǎo)致無法建立新連接可考慮調(diào)整net.ipv4.tcp_tw_reuse注意tcp_tw_recycle在NAT環(huán)境下有問題已從新內(nèi)核移除切勿使用。5. 擁塞控制與流量控制的間接證據(jù)TCP的擁塞控制Congestion Control和流量控制Flow Control是保證網(wǎng)絡(luò)穩(wěn)定的核心算法它們本身不直接產(chǎn)生“異?!眻笪牡錉顟B(tài)變化會通過報文模式體現(xiàn)出來。5.1 從報文序列推斷擁塞狀態(tài)擁塞控制算法如Cubic, BBR通過調(diào)整擁塞窗口cwnd來應(yīng)對網(wǎng)絡(luò)擁塞。我們無法直接從報文看到cwnd值但可以從傳輸模式推斷慢啟動階段連接建立初期或RTO超時后cwnd從1個MSS開始每收到一個ACK就翻倍。在Wireshark中你會看到數(shù)據(jù)包發(fā)送的間隔時間逐漸縮短發(fā)送“脈沖”越來越密集吞吐量指數(shù)增長。擁塞避免階段cwnd超過慢啟動閾值ssthresh后進(jìn)入線性增長階段。每RTT時間cwnd大約增加1個MSS。此時發(fā)送節(jié)奏趨于平穩(wěn)。發(fā)生擁塞通過重復(fù)ACK感知觸發(fā)快速重傳和快速恢復(fù)。cwnd會減半然后線性增長。在報文流中你會看到在快速重傳事件后發(fā)送速率有一個明顯的下降然后又開始緩慢爬升。通過超時感知觸發(fā)超時重傳cwnd會被重置為1個MSS并重新進(jìn)入慢啟動。這是最影響性能的情況在IO圖中會看到長時間的空閑RTO等待然后數(shù)據(jù)流像剛開始一樣緩慢啟動。Wireshark的“TCP Stream Graphs”中的“Time-Sequence Graph (Stevens)”或“Window Scaling Graph”是分析這些模式的利器。它們可以直觀地展示序列號隨時間增長的速度即吞吐量以及窗口大小的變化。5.2 流量控制與窗口大小的動態(tài)變化流量控制是通過接收方通告的窗口rwnd來實現(xiàn)的防止發(fā)送方淹沒接收方。除了之前提到的零窗口這種極端情況窗口大小的動態(tài)變化也值得關(guān)注。窗口收縮接收方在ACK中通告的窗口突然變小。這可能是因為接收方應(yīng)用突然進(jìn)行了一次大讀操作然后又暫?;蛘呓邮斩藘?nèi)存壓力導(dǎo)致緩沖區(qū)被系統(tǒng)收縮。頻繁的窗口大小劇烈波動可能意味著接收方應(yīng)用處理模式不穩(wěn)定。窗口關(guān)閉再打開即零窗口事件。分析其持續(xù)時間和頻率是關(guān)鍵。窗口始終很小即使網(wǎng)絡(luò)空閑通告窗口也一直很小。這可能是因為接收方應(yīng)用設(shè)置了非常小的SO_RCVBUF或者操作系統(tǒng)自動調(diào)整到了保守值。這在長肥網(wǎng)絡(luò)中是性能殺手。實操技巧在Wireshark中你可以添加自定義列來顯示“TCP Window size”和“Calculated window size”。結(jié)合IO圖可以清晰地看到窗口大小隨時間變化的曲線并將其與數(shù)據(jù)傳輸速率曲線對比。當(dāng)發(fā)送速率曲線緊貼窗口大小曲線時說明當(dāng)前流的瓶頸在于接收端的流量控制而非網(wǎng)絡(luò)擁塞或發(fā)送端性能。6. 綜合案例一次接口間歇性超時的排查實錄最后我們用一個虛擬但融合了多種異常的綜合案例來串聯(lián)上面的知識點(diǎn)。問題現(xiàn)象一個內(nèi)部微服務(wù)A調(diào)用服務(wù)B的接口監(jiān)控顯示該接口平均延遲正常50ms但有約1%的請求延遲超過2秒導(dǎo)致前端偶發(fā)性超時。排查過程初步定位查看服務(wù)A和B的日志超時請求在服務(wù)B的訪問日志中到達(dá)時間正常但處理時長確實激增。排除服務(wù)B應(yīng)用邏輯本身的問題如慢查詢因為同一時間其他請求正常。網(wǎng)絡(luò)抓包在服務(wù)A所在的宿主機(jī)上針對服務(wù)B的IP和端口使用tcpdump抓包并保存為pcap文件用Wireshark分析。過濾與聚焦在Wireshark中使用過濾表達(dá)式ip.addr 服務(wù)B_IP tcp.port 服務(wù)B端口聚焦問題流量。通過時間排序找到一次典型超時請求的TCP流右鍵 - Follow - TCP Stream。流分析發(fā)現(xiàn)端倪跟隨TCP流后在原始包列表視圖中可以清晰地看到這次交互的完整過程三次握手正常。服務(wù)A發(fā)送HTTP POST請求一個較大的JSON體約10KB。在傳輸這個POST包的過程中出現(xiàn)了多次TCP Dup ACK隨后跟隨著一個TCP Retransmission。這表明發(fā)生了單包丟失觸發(fā)了快速重傳。重傳后服務(wù)B回復(fù)了HTTP 200 OK但緊接著在同一個TCP連接內(nèi)服務(wù)A發(fā)送下一個請求時出現(xiàn)了TCP ZeroWindow包來自服務(wù)A深入分析重傳分析檢查重傳的包發(fā)現(xiàn)是POST請求中的一個TCP分片。時間戳顯示從第一次發(fā)送到重傳間隔約200msRTT的兩倍多符合快速重傳特征。這說明A到B的網(wǎng)絡(luò)路徑存在輕微丟包。零窗口分析為什么服務(wù)A作為客戶端會通告零窗口查看零窗口之前的包發(fā)現(xiàn)服務(wù)B的HTTP響應(yīng)體很小不可能填滿服務(wù)A的緩沖區(qū)。繼續(xù)往前看發(fā)現(xiàn)服務(wù)A在發(fā)送完P(guān)OST請求后幾乎同時收到了服務(wù)B的一個TCP包其窗口大小Win急劇減小到一個很小的值。但服務(wù)A似乎沒有理會這個窗口更新繼續(xù)以之前的速率發(fā)送后續(xù)的TCP包可能是ACK或后續(xù)請求導(dǎo)致服務(wù)B發(fā)出了零窗口通告。關(guān)聯(lián)推斷服務(wù)B在處理請求時可能由于瞬間的系統(tǒng)負(fù)載如GC導(dǎo)致其接收緩沖區(qū)緊張從而減小了通告窗口。而服務(wù)A的TCP??赡苡捎谀撤N原因如內(nèi)核參數(shù)tcp_adv_win_scale或中斷處理延遲沒有及時處理這個窗口更新導(dǎo)致了短暫的零窗口狀態(tài)。雖然零窗口只持續(xù)了不到10毫秒通過零窗口探測包可判斷但它發(fā)生在丟包重傳恢復(fù)的敏感時期。根因假設(shè)丟包觸發(fā)的快速重傳與對端瞬時壓力導(dǎo)致的窗口縮小事件在時間上重疊共同導(dǎo)致了本次請求的總延遲遠(yuǎn)高于正常RTT。丟包導(dǎo)致至少200ms的額外延遲而窗口關(guān)閉又阻塞了重傳恢復(fù)后數(shù)據(jù)的立即繼續(xù)發(fā)送增加了數(shù)十毫秒的等待。驗證與解決驗證丟包在服務(wù)A和服務(wù)B之間進(jìn)行長期的mtr或tcpping測試確認(rèn)是否存在穩(wěn)定的、低概率的丟包。結(jié)果發(fā)現(xiàn)經(jīng)過某個核心交換機(jī)時確有0.1%的丟包率。驗證窗口更新檢查服務(wù)B主機(jī)在問題時間點(diǎn)的系統(tǒng)監(jiān)控發(fā)現(xiàn)確實有周期性的CPU毛刺與GC周期吻合。解決方案與網(wǎng)絡(luò)團(tuán)隊確認(rèn)優(yōu)化交換機(jī)隊列配置解決丟包問題。優(yōu)化服務(wù)B的JVM GC參數(shù)減少STW時間降低應(yīng)用暫停對TCP緩沖區(qū)處理的影響??紤]在服務(wù)A與服務(wù)B之間啟用TCP的BBR擁塞控制算法如果內(nèi)核支持其對丟包的容忍度比Cubic更好在輕丟包環(huán)境下能保持更高吞吐量和更低延遲。這個案例告訴我們TCP異常報文很少孤立出現(xiàn)。一次性能問題往往是多個“小異?!痹阱e誤的時間疊加共振的結(jié)果。Wireshark的價值就在于它能將“接口超時”這個模糊的現(xiàn)象分解成“丟包重傳”、“窗口更新不及時”等具體的技術(shù)事件鏈讓排查工作有的放矢。