天天看點

《大咖講Wireshark網絡分析》—再來一個很妖的問題

本節書摘來自異步社群《大咖講wireshark網絡分析》一書中的再來一個很妖的問題,作者林沛滿,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

再來一個很妖的問題

大咖講wireshark網絡分析

有讀者問,“叔叔,你那些很“妖”的網絡問題是在哪找的?我也很感興趣,但是從來沒有遇到過。” 叔叔聽完這句話,頓時覺得心裡好苦——都是這些“妖怪”自己找上門的,我想躲都來不及,哪會主動去找啊!我們全球有幾千使用者,假如每位使用者每年遇到一次網絡故障,我就有看不完的包了。《wireshark網絡分析的藝術》中講到的那些案例,其實隻占極小部分,公司電腦裡還躺着幾百個案例等着整理呢。既然你們對“妖怪”問題有興趣,我就再分享一個吧。

上個月有個項目組找到我,說他們的用戶端往伺服器寫資料很慢,但是從伺服器讀資料卻一直很快。該環境中的用戶端、伺服器和交換機分别屬于不同廠商,三家人已經合作排查了一個月,實在沒有頭緒了,就來找我看看。作為一個叔叔,我要插播一點人生的經驗——凡是影響嚴重,大老闆非常關注,卻遲遲未能解決的難題,你要盡一切可能承擔下來。要知道你平時處理一百件小事都不會有人注意,個人技術也不會提高多少,但是解決掉一個大問題就足以令人刮目相看,自己的技術也會大有長進。

項目組其實已經做了不少有價值的測試,總結如下:

1.如果跳過交換機,直接把用戶端和伺服器用網線連起來,問題仍然存在。這說明交換機可以排除掉,隻需專注用戶端和伺服器。

2.該用戶端寫資料到其他類型的裝置時速度很快,似乎說明了用戶端是好的。

3.其他類型的裝置寫資料到該伺服器上時速度也很快,似乎說明了伺服器也是好的。

綜上所述,這一對用戶端和伺服器就像命理相克似的,平時雙方都是工作正常的,但是碰到一起就出問題。我的老讀者們可能已經想到了一些可能性:是不是有delayed ack和nagle算法的沖突啊?還是網口的speed/duplex不一緻啊?可惜都不是,項目組早就查遍了。事到如今,隻好抓個網絡包來分析了。

這個項目團隊實在給力,在兩邊分别抓了幾十個 tcpdump檔案,合起來有 100 gb。解壓縮的時候我的内心是崩潰的,他們說之是以抓了這麼多,是因為該症狀隻是偶爾出現,是以不得不抓了很長時間。要想在 100 gb的網絡包裡找到偶爾發作的性能問題,對眼睛和耐心都是挑戰,幸好wireshark有個功能在此時可以派上用場:

打開從用戶端抓到的包,單擊菜單statistics→tcp streamgraph→time-sequence graph (stevens),就可以生成一個傳輸狀态圖了(不要問我“stevens”是什麼意思,我猜這是wireshark在向偉大的技術作家richard stevens緻敬)。

在理想狀況下,随着資料的勻速傳輸, sequence應該逐漸增加,進而形成一根較直的斜線。這次抓到的大多數tcpdump的确都是這樣的,如圖1所示。

《大咖講Wireshark網絡分析》—再來一個很妖的問題

note:中間有一小段空白,表示那段時間的網絡包沒有抓到,這種現象可以忽視。

檢查了幾個tcpdump後,我終于遇到一個異常的,請看圖2。大約從 3.0 秒到 11.0 秒之間,sequence幾乎沒有增加,這說明當時傳輸幾乎停滞了。我們隻要找到當時發生了什麼,就能解決問題。

《大咖講Wireshark網絡分析》—再來一個很妖的問題

在圖2中單擊sequence曲線的 3.0 秒處,就能定位到相應的包号了。請看圖3,定位到了no.264536上。

《大咖講Wireshark網絡分析》—再來一個很妖的問題

仔細來分析一下圖3,伺服器在no.264535中聲明它的tcp接收視窗有 3145728 位元組,可是用戶端在no.264536中隻發了9657個位元組就停下來了,這說明它的擁塞視窗隻有 9657 個位元組,是用戶端的擁塞視窗限制了傳輸速度,而不是伺服器的接收視窗。接下來的包也類似,伺服器在no.264537中聲明了接收視窗仍然是 3145728 位元組,然後用戶端在no.264538中發出了 9874 個位元組,隻比上一次增加了 9874 - 9657 = 217 位元組。如此反複,後面的包你們自己看吧。

注意:

本環境中用戶端和伺服器的mss都是1460,我們之是以能看到大于 1460 位元組的包,是因為用戶端啟用了lso(large segment offload)。

可見當時之是以傳得這麼慢,是因為用戶端的擁塞視窗一直很小,而且增長得特别慢。學過tcp協定的讀者應該都知道,在慢啟動階段雖然擁塞視窗很小,但是增長得很快,呈翻倍式增長。比如上一次發了 9657 位元組,那下一次就應該是 9657 × 2 = 19314 位元組。而擁塞避免階段的擁塞視窗一般已經比較大,而且是以mss(在此連接配接中為 1460 位元組)增長的,再怎麼樣也不會隻增長 217 個位元組。圖4表示了擁塞視窗在不同階段的增長方式(橫軸的機關是往返時間,縱軸的機關是mss):

《大咖講Wireshark網絡分析》—再來一個很妖的問題

那麼這問題就應該由用戶端來負責了,他們的tcp算法肯定有問題。在“罪證”面前,用戶端的廠商也承認了,不過他們也說了,協定棧的問題研究起來沒那麼快,說不定要幾個月。而且為什麼這台用戶端寫到别的伺服器就沒有問題呢?會不會是伺服器上的其他問題觸發的?

好人做到底。我覺得他們說的也有點道理,那就繼續研究吧。仔細看圖3,每當用戶端收到伺服器的确認包,就立即把資料發出去,比如no.264535和no.264536之間的時間差幾乎可以忽略。而用戶端發出資料之後,要等很久才能收到伺服器的确認,比如no.264536和no.264537之間的時間差竟然有40毫秒。這個延遲在區域網路中算是很可觀的,為什麼會這樣呢?我也看不出來。

目前為止,我們分析的網絡包都是在用戶端抓的,接下來就去分析一下伺服器上抓的tcpdump吧。可惜的是項目組在伺服器上抓包時,并沒有重制出性能問題,也就是說我手頭這些包都是好的,隻能死馬當活馬醫,盡可能看看了。請看圖5,在正常情況下,伺服器的響應速度很快,用戶端的擁塞視窗增長得也很快(4344724010136),包與包之間幾乎都沒有時間差。

《大咖講Wireshark網絡分析》—再來一個很妖的問題

這圖是否能給我們一些啟示呢?還真的能。如前面所說,用戶端和伺服器的mss都是 1460 位元組,我有tcp三次握手過程為證(見圖6)。

《大咖講Wireshark網絡分析》—再來一個很妖的問題

這說明一個資料包從用戶端的網卡發出來時,tcp層最多攜帶 1460 位元組的資料。而從圖5卻可以看到,伺服器收到包的時候,居然是 4344 位元組、7240 位元組、10136 位元組……這是怎麼回事呢?我在上本書裡隻介紹過lso的工作原理,但沒有介紹過lro(large receive offload)。它是網卡上的一個功能,可以幫助伺服器接收偏小的tcp包,緩沖處理成偏大的tcp包再交給伺服器。也就是說,用戶端收到的那些确認包,其實是伺服器網卡緩沖處理了資料包之後才發出的。會不會是網卡緩沖處理時出了bug,導緻多花了40毫秒呢?我們隻需要在網卡上關閉lro就知分曉了。我跟項目組打了個電話,讓他們執行以下指令來關閉:

ethtool -k eth3 lro off

果然從此之後,他們就再也無法重制那個性能問題了,可以喝啤酒吃炸雞慶祝了。看到這裡你也許會問,用戶端的協定棧算法問題不是還沒有解決嗎?為什麼症狀就消失了呢?這個問題的精妙之處就在此處:圖3中伺服器的響應很慢,用戶端的擁塞視窗增加得也很慢;而圖5中伺服器的響應很快,用戶端的擁塞視窗增加得也很快。這是否說明用戶端其實采用了一種特殊的tcp算法,使擁塞視窗和響應時間挂鈎呢?直到問題解決之後,我才意識到這一點。其實我在《wireshark網絡分析就這麼簡單》中介紹的tcp vegas就是類似的,摘錄如下:

“……vegas則引入了一個全新的理念。本書之前介紹過的所有算法,都是在丢包後才調節擁塞視窗的。vegas卻獨辟蹊徑,通過監控網絡狀态來調整發包速度,進而實作真正的'擁塞避免'。它的理論依據也并不複雜:當網絡狀況良好時,資料包的rtt(往返時間)比較穩定,這時候就可以增大擁塞視窗;當網絡開始繁忙時,資料包開始排隊,rtt就會變大,這時候就需要減小擁塞視窗了。該設計的最大優勢在于,在擁塞真正發生之前,發送方已經能通過rtt預測到,并且通過減緩發送速度來避免丢包的發生。

與别的算法相比,vegas就像一位敏感、穩重、謙讓的君子。我們可以想象當環境中所有發送方都使用vegas時,總體傳輸情況是更穩定、更高效的,因為幾乎沒有丢包會發生。而當環境中存在vegas和其他算法時,使用vegas的發送方可能是性能最差的,因為它最早探測到網絡繁忙,然後主動降低了自己的傳輸速度。這一讓步可能就釋放了網絡的壓力,進而避免其他發送方遭遇丢包。這個情況有點像開車,如果路上每位司機的車品都很好,謙讓守規矩,則整體交通狀況良好;而如果一位車品很好的司機跟一群車品很差的司機一起開車,則可能被頻繁加塞,最後成了開得最慢的一個。”

在本案例中,由于伺服器上lro導緻的 40 毫秒延遲,使得用戶端以為網絡上存在擁塞,是以就放慢了速度。而在lro工作正常的環境中,自然不會有問題。前面說它們命理相克,正是出于這個原因。

本文僅用于學習和交流目的,不代表異步社群觀點。非商業轉載請注明作譯者、出處,并保留本文的原始連結。

繼續閱讀