跳轉到主要內容
工程的博客

TCP協議棧的冒險:發現性能回歸TCP麻袋漏洞修複

分享這篇文章

上個月,我們宣布磚的平台體驗網絡性能回歸是因為LinuxBeplay体育安卓版本的補丁TCP麻袋漏洞。回歸是觀察不到0.2%的情況下運行時數據磚運行時(DBR)亞馬遜網絡服務(AWS)平台。Beplay体育安卓版本在這篇文章中,我們將會深入研究分析,確定了TCP協議棧是退化的根源。我們將討論我們看到的症狀,穿過我們如何調試TCP連接,並解釋在Linux源代碼的根本原因。

作為一個快速注意在跳之前,規範正在一個Ubuntu 16.04圖像解析這些性能回歸。我們計劃更新磚平台一旦圖像是可用的和已通過我們的回歸測試。Beplay体育安卓版本

一個失敗的基準

我們第一次提醒當我們的基準之一成為6 x慢。回歸出現升級之後我們使用Amazon Machine Image (AMI)將Ubuntu的TCP麻袋漏洞修複。

性能測試操作係統S3寫,包括TCP袋性能回歸。
磚平台的ami - 2.102Beplay体育安卓版本圖像(紅色)包括TCP袋性能回歸。它與運行平均6 x低~ 16分鍾。上麵的圖表顯示累計時間超過20分。

失敗的基準大DataFrame S3通過寫道磚文件係統(DBFS)使用Apache火花的保存函數。

火花.range (10*億).write.format(“鋪”).mode(“覆蓋”).save (“dbfs:/ tmp /測試”)

Apache火花階段執行保存操作有極端的任務傾斜。一個流浪者任務花了15分鍾,而其餘完成在不到1秒。

詳細分析網絡性能回歸TCP袋造成的漏洞修複。
火花UI允許我們檢測到Apache火花階段運行保存操作有極端任務傾斜。

不安全的問題消失當回滾AMI沒有TCP麻袋漏洞修複。

調試TCP連接

為了弄清楚為什麼流浪者任務花了15分鍾,我們需要抓住它的行動。我們重新基準監控火花UI時,知道的任務之一保存操作會在幾分鍾內完成。在這一階段的任務進行排序狀態列,它沒過多久,那裏隻有一個任務處於運行狀態。我們發現傾斜任務和IP地址主機列指出我們的遺囑執行人經曆回歸。

調試網絡TCP麻袋漏洞修複而導致的性能問題。
火花UI引導我們的IP地址執行程序運行流浪者的任務。

與IP地址,我們ssh到執行人看到發生了什麼。由於懷疑網絡問題AmazonS3Exception我們以前見過的錯誤集群日誌,我們跑netstat看活動的網絡連接。

~# netstat活躍的互聯網連接(w/o服務器)原型Recv- - - - - -問發送- - - - - -當地的地址外國地址狀態tcp6816年99571年知識產權-10年0-144年-224年。你:42464年s3- - - - - -我們- - - - - -西2- - - - - -r- - - - - -w。:https CLOSE_WAIT

一個TCP連接到一個S3服務器被卡住了CLOSE_WAIT狀態。這種狀態表明服務器傳輸數據和關閉了連接,但客戶仍然有更多的數據發送。的套接字連接有97 kb的數據等待發送。

同時監控,套接字的狀態,直到保存操作完成後15分鍾,我們注意到發送隊列的大小沒有改變。它保持在97 kb。S3服務器要麼不承認或執行器節點的數據發送數據失敗。我們使用黨衛軍更詳細的套接字。

~# ss - a - t - m - o -信息CLOSE-WAIT816年99571年::飛行符:10.0144.224:42464年::飛行符:52.218234.25https計時器:(,1min37sec,13)skmem:(r9792、rb236184 t0、tb46080 f732, w103971, o0, bl0)立方wscale袋:8,7rto:120000年補償:13rtt:0.379/0.055ato:40海量存儲係統(mss)中:1412年cwnd:1ssthresh:23bytes_acked:1398838bytes_received:14186年segs_out:1085年segs_in:817年發送29.8Mbps lastsnd:592672年lastrcv:552644年lastack:550640年pacing_rate4759.3Mbps unacked:80年損失:24開除:56rcv_space:26883年

使用黨衛軍讓我們看看插座的內存使用量(- m),TCP特定信息(——信息)和定時器信息(- o)。讓我們來看看這個調查的重要的數字:

  • 計時器:(1)min37sec, 13)——直到下一個重傳(1分鍾37秒)和完成傳輸嚐試(13)。
  • tb46080 -套接字的當前發送緩衝區大小的字節(45 kb)。這地圖sk_sndbuf在Linux套接字結構
  • w103971——該套接字所消耗的內存寫緩衝區字節(101 kb)。這地圖sk_wmem_queued在Linux套接字結構。
  • 海量存儲係統(mss)中:1412——連接最大細分市場大小的字節。
  • lastsnd: 591672——自從上次數據包發送時在毫秒(9分51秒)。

這個套接字的狀態的快照表明它已經13失敗重傳和下一個嚐試將嚐試在1分37秒。這是奇怪的,但是,考慮到TCP重發在Linux中之間的最長時間是2分鍾和套接字沒有發送一個數據包在過去9分51秒。服務器不是承認失敗重發;客戶的重發甚至不使它的線!

在套接字被困在這種狀態下,我們觀看了傳輸計數器蜱蟲15(默認設置net.ipv4.tcp_retries2),直到關閉套接字。發送隊列和寫隊列大小從未改變,自從上次包發送的時候從來沒有下降,表明該套接字繼續發送數據失敗。一旦關閉套接字,S3客戶重試機製踢的和數據傳輸成功。

這種行為匹配和15分鍾的這是我們的基準的流浪者的任務完成。與tcp_retries2設置為15,TCP_RTO_MIN設置為200毫秒,TCP_RTO_MAX設置為120秒,一個指數倒扣在重試之間,需要924.6秒,或超過15分鍾,超時的連接。

傳輸嚐試記錄在調試錯誤的網絡套接字。
默認的TCP傳輸進度。重發間隔起價200 ms和馬克斯的指數級增長的120年代,直到15分鍾後關閉套接字失敗重發。

袋子在TCP痕跡

與斜解釋為重新傳輸超時15分鍾的任務,我們需要理解為什麼客戶端無法重新發送數據包到S3服務器。我們收集所有的TCP痕跡執行人而調試基準和那裏尋找答案。

sudo tcpdump nns淨52.218.0.0/16 - w awstcp.pcap

tcpdump以上命令捕獲所有流量與S3子網(52.218.0.0/16)。我們下載了.pcap文件從傾斜的任務的執行者和分析使用Wireshark

TCP連接與本地端口42464 -被困在CLOSE_WAITS3狀態——客戶端試圖發送1.4 mb的數據。第一個1.3 mb轉移成功地在600毫秒,但隨後S3服務器錯過了一些片段和送一袋。SACK表示,22138個字節是錯過了(ACK基地之間的差異和解雇的左邊緣)。

缺少從錯誤的網絡傳輸字節。
TCP堆棧跟蹤顯示,S3服務器發送一袋後失蹤21 kb的數據。

後客戶端發送第一次傳輸所有價值1.4 mb的外向TCP段,沉默了40秒的連接。第一個7重傳的嚐試失蹤21 kb應該在這段時間內觸發,貸款進一步證明客戶端無法通過電線發送數據包。最後發送的服務器包袋相同的信息,這表明,目前尚未收到丟失的數據。這使得客戶端進入CLOSE_WAIT狀態,即使允許客戶端傳輸數據在這個狀態,事實並非如此。這個連接的TCP不再跟蹤顯示數據包。不被承認的22138字節從來沒有重新傳輸。

鰭包袋的信息,表示,目前尚未收到缺失的數據。
S3服務器發送一個鰭包袋的信息表明這是失蹤21 kb的數據。TCP跟蹤顯示,客戶從來沒有轉播的丟失的數據。

添加這些77433年解雇22138字節字節(從左邊緣減去右邊緣),我們得到了99571字節。這個數字看起來應該很熟悉。它是套接字的大小發送隊列中列出netstat輸出。這引出了第二個問題。為什麼沒有解雇了75 kb的數據從套接字的發送隊列中刪除嗎?服務器已經確認接收;客戶端不需要保留它。

不幸的是,TCP跟蹤沒有告訴我們為什麼重發失敗,隻添加了一個額外的問題需要回答。我們打開Ubuntu 16.04源代碼,學習更多的知識。

剖析了TCP協議棧

一個Linux補丁為了解決TCP麻袋漏洞一個if語句添加到tcp_fragment ()函數。它是為了限製條件TCP協議棧碎片套接字的重傳隊列來防止惡意的手工袋包。首先我們看,因為它已經固定一次。

規範的補丁改變允許分裂的套接字緩衝區,包括未寄出的包。
規範的補丁改變允許分裂的套接字緩衝區,包括未寄出的包。

即使有此修複,我們仍然看到問題。7月底,另一個解決發表新版本的Linux。作為我們的ami使用Ubuntu 16.04規範4.4.0 Linux內核的補丁,補丁,建立了一個定製的Ubuntu內核。我們的性能問題消失了。

Backpackport第二補丁修複造成的性能回歸最初的TCP麻袋漏洞修複。
第二個補丁的補丁修複造成的性能回歸最初的TCP麻袋漏洞修複。

仍然忽視問題的根源,因為我們不知道這四個條件的if語句固定我們的問題,我們建立了多個自定義映像,隔離每個條件。圖片隻有第一個條件——修改sk_wmem_queued檢查,證明足以解決我們的問題。

tcp_fragment的if語句()發送有限的變化,解決性能問題。
tcp_fragment的if語句()發送有限的變化,解決性能問題。

變更的提交消息說,一個128 kb的開銷了sk_sndbuf形成的極限,因為“tcp_sendmsg ()tcp_sendpage ()可能會過度sk_wmem_queued約一個完整TSO skb (64 kb大小)。“這意味著sk_wmem_queued可以合理地超過sk_sndbuf高達64 kb。這是我們所看到在我們的套接字。如果你記得黨衛軍輸出,發送緩衝區的大小是46080字節和寫隊列是103971字節(56 kb)的差異。我們寫一半的隊列(注意正確的轉變條件)大於發送緩衝區,我們滿足原修複的if條件。nstat證實這一點,因為我們看到了TCPWQUEUETOOBIG數記錄為179。

~# nstat | grep“TcpExtTCPWqueueTooBig”TcpExtTCPWqueueTooBig179年0.0

證實了我們確實是失敗的tcp_fragment (),我們想找出這可能導致重傳失敗的原因。查找的堆棧重新發送代碼路徑我們看到,如果一個套接字緩衝區的長度大於當前MSS 1412字節(在我們的例子中),tcp_fragment ()重傳之前被調用。如果失敗,重新傳輸增量TCPRETRANSFAIL計數器(我們是在143年)中止重傳整個隊列的套接字緩衝區。這就是為什麼我們沒有觀察到任何重發的21個kb的數據不被承認的。

這使得解雇了75 kb的數據。為什麼沒有從這些包回收內存嗎?它將降低了寫隊列的大小,使分裂企圖在傳輸成功。唉,也稱解雇處理tcp_fragment ()當一個套接字緩衝區並不是完全袋內邊界,這樣就可以免費承認部分。當一個分裂失敗時,該處理程序爆發沒有檢查的套接字緩衝區。這可能是為什麼承認的75 kb數據沒有公布。如果不被承認的21個kb共享一個套接字緩衝區被解職的第一部分數據,它需要碎片回收。沒有相同的if條件tcp_fragment (),SACK處理程序將會中止。

經驗教訓

反思我們的旅程通過發現、調查和根本原因分析,幾點突出:

  • 考慮整個堆棧。我們認為理所當然,Ubuntu提供一個安全的和穩定的平台為我們的集群。Beplay体育安卓版本最初我們的基準測試失敗時,我們很自然地開始尋找線索在最近的自己的變化。隻有在發現隨後Linux TCP補丁,我們開始質疑位降低堆棧。
  • 基準是數字;日誌記錄是至關重要的。我們已經知道,但值得重申。我們的基準簡單告訴我們這個平台是6 x慢。Beplay体育安卓版本它沒有告訴我們去哪裏看。火花日誌報告S3套接字超時異常給我們第一次真正的提示。基準,提醒等日誌異常會大大減少最初的調查時間。
  • 使用正確的工具。15分鍾的套接字超時難住了我們一段時間。我們知道netstat,但後來才知道黨衛軍。後者提供更多細節關於套接字的狀態和重傳失敗明顯。它也幫助我們更好地理解TCP跟蹤期望的重發也失蹤了。

我們也學到了很多關於Linux TCP協議棧在這深潛水。盡管磚不希望很快開始Linux提交補丁,我們欠我們的客戶和Linux社區來支持我們早些時候聲稱,一個操作係統補丁需要修複我們的性能回歸。beplay体育app下载地址好消息是,最新的4.4.0補丁解決這個問題,一位官員Ubuntu 16.04修複在望。

免費試著磚
看到所有工程的博客的帖子
Baidu
map