❶ TCP之Nagle、Cork、Delay ACK(延遲確認)
[TOC]
TCP協議中的Nagle演算法
TCP中的Nagle演算法
linux下TCP延遲確認(Delayed Ack)機制導致的時延問題分析
TCP-IP詳解:Delay ACK
Nagle演算法為了避免網路中存在太多的小數據包,盡可能發送大的數據包。定義為在任意時刻,最多隻有一個未被確認的小段。小段為小於MSS尺寸的數據塊,未被確認是指數據發出去後未收到對端的ack。
Nagle演算法是在網速較慢的時代的產物,目前的網路環境已經不太需要該機制,該演算法在linux系統中默認關閉。
1)如果包長度達到MSS,則允許發送;
2)如果該包含有FIN,則允許發送;
3)設置了TCP_NODELAY選項,則允許發送;
4)未設置TCP_CORK選項時,若所有發出去的包均被確認,或所有發出去的小數據包(包長度小於MSS)均被確認,則允許發送。
對於規則4),就是說要求一個TCP連接上最多隻能有一個未被確認的小數據包,在該分組的確認到達之前,不能發送其他的小數據包。如果某個小分組的確認被延遲了(案例中的40ms),那麼後續小分組的發送就會相應的延遲。也就是說延遲確認影響的並不是被延遲確認的那個數據包,而是後續的應答包。
tcp默認使用nagle演算法,最大限度的進行緩存。
優點 :避免網路中充斥著許多小數據塊,降低網路負載,減少網路擁塞,提高網路吞吐
缺點 :客戶端的延遲會增加,實時性降低,不適合延時要求盡量小的場景;且對於大文件傳輸這種場景,會降低傳輸速度。
用TCP_NODELAY選項可以禁止Negale 演算法。此時,應用程序向內核遞交的每個數據包都會立即發送出去。需要注意的是,雖然禁止了Negale 演算法,但網路的傳輸仍然受到TCP確認延遲機制的影響。
TCP在接收到對端的報文後,並不會立即發送ack,而是等待一段時間發送ack,以便將ack和要發送的數據一塊發送。當然ack不能無限延長,否則對端會認為包超時而造成報文重傳。linux採用動態調節演算法來確定延時的時間。
TCP在何時發送ACK的時候有如下規定:
優點 :減少了數據段的個數,提高了發送效率
缺點 :過多的delay會拉長RTT(往返時延)
可以通過TCP_QUICKACK這個選項來啟動快速ACK:
所謂的CORK就是塞子的意思,形象地理解就是用CORK將連接塞住,使得數據先不發出去,等到拔去塞子後再發出去。Cork演算法與Nagle演算法類似,也有人把Cork演算法稱呼為super-Nagle。Nagle演算法提出的背景是網路因為大量小包小包而導致利用率低下產生網路擁塞,網路發生擁塞的時候性能還會進一步下降,因此Nagle演算法通過ACK確認包來觸發新數據包的發送(ACK確認包意味著對端已經接收到了一個數據包,即有一個數據包已經離開中間網路,此時可以在向中間網路注入一個數據包塊,這稱呼為self-clocking)。Cork演算法則更為激進,一旦打開Cork演算法,TCP不關注是否有收到ACK報文,只要當前緩存中累積的數據量不足以組成一個full-sized數據包就不會將數據包發出,直到一個RTO超時後才會把不滿足一個full-sized的數據包發出去(實際上是通過一個persist timer來設置的這個RTO定時時間,persist timer超時的時候就會強制發送)。
linux中可以通過TCP_CORK選項來設置socket打開Cork演算法。TCP_NODELAY選項和TCP_CORK選項在linux早期版本是互斥的,但目前最新的linux版本已經可以同時打開這兩個選項了,但是TCP_CORK選項的優先順序要比TCP_NODELAY選項的優先順序要高。
Nagle演算法和CORK演算法非常類似,但是它們的著眼點不一樣,Nagle演算法主要避免網路因為太多的小包(協議頭的比例非常之大)而擁塞,而CORK演算法則是為了提高網路的利用率,使得總體上協議頭佔用的比例盡可能的小.如此看來這二者在避免發送小包上是一致的,在用戶控制的層面上,Nagle演算法完全不受用戶socket的控制,你只能簡單的設置TCP_NODELAY而禁用它,CORK演算法同樣也是通過設置或者清除TCP_CORK使能或者禁用之,然而Nagle演算法關心的是網路擁塞問題,只要所有的ACK回來則發包,而CORK演算法卻只關心內容,在前後數據包發送間隔很短的前提下(很重要,否則內核會幫你將分散的包發出),即使你是分散發送多個小數據包,你也可以通過使能CORK演算法將這些內容拼接在一個包內,如果此時用Nagle演算法的話,則可能做不到這一點.
優點 :提高網路的利用率
缺點 :對實時性有影響
使用TCP_CORK參數進行配置
❷ liunx怎麼解決tcp連接timeout過長
不明白你說的老化時間,關於established的時間,摘錄個別人的心得吧 TCP協議有個超時重傳機制,想必大家都比較熟悉。TCP協議是一種傳輸可靠的協議,因此這個機制是必不可少的。那麼今天要探討的是在發送隊列還有數據的情況下,網路連接異常斷開後,協議棧是到底是怎樣來處理這些數據的,資源又是怎樣被回收的呢? 我這里先給出幾個測試的結果: 1、修改linux系統下的tcp_retries2為1,當socket發送隊列有一定數據時,突然切斷網線,造成異常斷鏈的場景,此時,大約過了1秒,用netstat觀察established的連接消失; 2、繼續把該參數修改為15,重復上面的實驗,發現大約過了15分鍾後,established的連接才斷開; 3、把參數再次修改為5,大約過了7秒,連接消失 /proc/sys/net/ipv4/tcp_retries2 思考:TCP的超時後,重傳的次數和重傳的時間間隔是影響連接斷開的主要參數。但是,從上面的實驗數據來看,似乎沒有什麼規律。查閱linux幫助文檔,發現這個重傳的時間間隔與RTO有關,而這個參數又是協議棧通過檢測網路狀況而實時改變的。
❸ TCP協議總結
Transmission Control Protocol,傳輸控制協議,是一種面向連接的、可靠的、基於位元組流的傳輸層通信協議
TCP協議的目的是: 在不可靠傳輸的IP層之上建立一套可靠傳輸的機制。 TCP的可靠只是對於它自身來說的, 甚至是對於socket介面層, 兩個系統就不是可靠的了, 因為發送出去的數據, 沒有確保對方真正的讀到(所以要在業務層做重傳和確認機制)。
可靠傳輸的第一要素是 確認 , 第二要素是 重傳 , 第三要素是 順序 。 任何一個可靠傳輸的系統, 都必須包含這三個要素。 數據校驗 也是必要的。
傳輸是一個廣義的概念, 不局限於狹義的網路傳輸, 應該理解為通信和交互. 任何涉及到通信和交互的東西, 都可以借鑒TCP的思想。無論是在UDP上實現可靠傳輸或者創建自己的通信系統,無論這個系統是以API方式還是服務方式,只要是一個通信系統,就要考慮這三個要素。
SeqNum的增加是和傳輸的位元組數相關的。 上圖中,三次握手後,來了兩個Len:1440的包,而第二個包的SeqNum就成了1441。然後第一個ACK回的是1441(下一個待接收的位元組號),表示第一個1440收到了。
網路上的傳輸是沒有連接的,包括TCP也是一樣的 。而TCP所謂的「連接」,其實只不過是在通訊的雙方維護一個「連接狀態」,讓它看上去好像有連接一樣。所以,TCP的狀態變換是非常重要的。
查看各種狀態的數量
ss -ant | awk '{++s[$1]} END {for(k in s) print k,s[k]}'
通過三次握手完成連接的建立
三次握手的目的是交換通信雙方的初始化序號,以保證應用層接收到的數據不會亂序,所以叫SYN(Synchronize Sequence Numbers)。
ISN是不能hard code的,不然會出問題的。比如:如果連接建好後始終用1來做ISN,如果client發了30個segment過去,但是網路斷了,於是client重連,又用了1做ISN,但是之前連接的那些包到了,於是就被當成了新連接的包,此時,client的Sequence Number可能是3,而Server端認為client端的這個號是30了。全亂了。RFC793中說,ISN會和一個假的時鍾綁在一起,這個時鍾會在每4微秒對ISN做加一操作,直到超過232,又從0開始。這樣,一個ISN的周期大約是4.55個小時。因為,我們假設我們的TCP Segment在網路上的存活時間不會超過Maximum Segment Lifetime(MSL),所以,只要MSL的值小於4.55小時,那麼,我們就不會重用到ISN。
如果Server端接到了Clien發的SYN後回了SYN-ACK,之後Client掉線了,Server端沒有收到Client返回的ACK,那麼,這個連接就處於一個中間狀態,即沒成功,也沒失敗。於是,Server端如果在一定時間內沒有收到的ACK會重發SYN-ACK。在Linux下,默認重試次數為5次,重試的間隔時間從1s開始每次都翻番,5次的重試時間間隔為1s, 2s, 4s, 8s, 16s,總共31s,第5次發出後還要等32s都知道第5次也超時了,所以,總共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 26 -1 = 63s,TCP才會斷開這個連接。
客戶端給伺服器發了一個SYN後,就下線了,於是伺服器需要默認等63s才會斷開連接,這樣,攻擊者就可以把伺服器的SYN連接的隊列耗盡,讓正常的連接請求不能處理。
於是,Linux下給了一個叫tcp_syncookies的參數來應對這個事:當SYN隊列滿了後,TCP會通過源地址埠、目標地址埠和時間戳打造出一個特別的Sequence Number發回去(又叫cookie),此時伺服器並沒有保留客戶端的SYN包。如果是攻擊者則不會有響應,如果是正常連接,則會把這個SYN Cookie發回來,然後服務端可以通過cookie建連接(即使你不在SYN隊列中)。
千萬別用tcp_syncookies來處理正常的大負載的連接的情況。因為sync cookies是妥協版的TCP協議,並不嚴謹。應該調整三個TCP參數:tcp_synack_retries減少重試次數,tcp_max_syn_backlog增大SYN連接數,tcp_abort_on_overflow處理不過來乾脆就直接拒絕連接
因為TCP是全雙工的,因此斷開連接需要4次揮手,發送方和接收方都需要發送Fin和Ack。如果兩邊同時斷連接,那就會就進入到CLOSING狀態,然後到達TIME_WAIT狀態。
指的是報文段的最大生存時間,如果報文段在網路中活動了MSL時間,還沒有被接收,那麼會被丟棄。關於MSL的大小,RFC 793協議中給出的建議是兩分鍾,不過實際上不同的操作系統可能有不同的設置,以Linux為例,通常是半分鍾,兩倍的MSL就是一分鍾,也就是60秒
主動關閉的一方會進入TIME_WAIT狀態,並且在此狀態停留兩倍的MSL時長。由於TIME_WAIT的存在,大量短連接會佔有大量的埠,造成無法新建連接。
主動關閉的一方發出 FIN包,被動關閉的一方響應ACK包,此時,被動關閉的一方就進入了CLOSE_WAIT狀態。如果一切正常,稍後被動關閉的一方也會發出FIN包,然後遷移到LAST_ACK狀態。
CLOSE_WAIT狀態在伺服器停留時間很短,如果你發現大量的 CLOSE_WAIT狀態,那麼就意味著被動關閉的一方沒有及時發出FIN包。
TCP要保證所有的數據包都可以到達,所以,必需要有重傳機制。
接收端給發送端的Ack確認只會確認最後一個連續的包 ,比如,發送端發了1,2,3,4,5一共五份數據,接收端收到了1,2,於是回ack 3,然後收到了4(注意此時3沒收到),此時的TCP會怎麼辦?我們要知道,因為正如前面所說的,SeqNum和Ack是以位元組數為單位,所以ack的時候,不能跳著確認,只能確認最大的連續收到的包,不然,發送端就以為之前的都收到了
但總體來說都不好。因為都在等timeout,timeout可能會很長
不以時間驅動,而以數據驅動重傳
如果包沒有連續到達,就ack最後那個可能被丟了的包,如果發送方連續收到3次相同的ack,就重傳
Selective Acknowledgment, 需要在TCP頭里加一個SACK的東西,ACK還是Fast Retransmit的ACK,SACK則是匯報收到的數據碎版,在發送端就可以根據回傳的SACK來知道哪些數據到了,哪些沒有收到
重復收到數據的問題,使用了SACK來告訴發送方有哪些數據被重復接收了
經典演算法:Karn/Partridge演算法,Jacobson/Karels演算法
TCP必需要知道網路實際的數據處理帶寬或是數據處理速度,這樣才不會引起網路擁塞,導致丟包
Advertised-Window :接收端告訴發送端自己還有多少緩沖區可以接收數據。於是發送端就可以根據這個接收端的處理能力來發送數據,而不會導致接收端處理不過來
接收端LastByteRead指向了TCP緩沖區中讀到的位置,NextByteExpected指向的地方是收到的連續包的最後一個位置,LastByteRcved指向的是收到的包的最後一個位置,我們可以看到中間有些數據還沒有到達,所以有數據空白區。
發送端的LastByteAcked指向了被接收端Ack過的位置(表示成功發送確認),LastByteSent表示發出去了,但還沒有收到成功確認的Ack,LastByteWritten指向的是上層應用正在寫的地方。
接收端在給發送端回ACK中會匯報自己的AdvertisedWindow = MaxRcvBuffer – LastByteRcvd – 1;
收到36的ack,並發出了46-51的位元組
如果Window變成0了,發送端就不發數據了
如果發送端不發數據了,接收方一會兒Window size 可用了,怎麼通知發送端呢:TCP使用了Zero Window Probe技術,縮寫為ZWP,也就是說,發送端在窗口變成0後,會發ZWP的包給接收方,讓接收方來ack他的Window尺寸,一般這個值會設置成3次,每次大約30-60秒。如果3次過後還是0的話,有的TCP實現就會發RST把鏈接斷了。
如果你的網路包可以塞滿MTU,那麼你可以用滿整個帶寬,如果不能,那麼你就會浪費帶寬。避免對小的window size做出響應,直到有足夠大的window size再響應。
如果這個問題是由Receiver端引起的,那麼就會使用David D Clark』s 方案。在receiver端,如果收到的數據導致window size小於某個值,可以直接ack(0)回sender,這樣就把window給關閉了,也阻止了sender再發數據過來,等到receiver端處理了一些數據後windows size大於等於了MSS,或者receiver buffer有一半為空,就可以把window打開讓send 發送數據過來。
如果這個問題是由Sender端引起的,那麼就會使用著名的 Nagle』s algorithm。這個演算法的思路也是延時處理,他有兩個主要的條件:1)要等到 Window Size >= MSS 或是 Data Size >= MSS,2)等待時間或是超時200ms,這兩個條件有一個滿足,他才會發數據,否則就是在攢數據。
TCP_CORK是禁止小包發送,而Nagle演算法沒有禁止小包發送,只是禁止了大量的小包發送
TCP不是一個自私的協議,當擁塞發生的時候,要做自我犧牲
擁塞控制的論文請參看 《Congestion Avoidance and Control》
主要演算法有:慢啟動,擁塞避免,擁塞發生,快速恢復,TCP New Reno,FACK演算法,TCP Vegas擁塞控制演算法
TCP網路協議及其思想的應用
TCP 的那些事兒(上)
TCP 的那些事兒(下)
tcp為什麼是三次握手,為什麼不是兩次或四次?
記一次TIME_WAIT網路故障
再敘TIME_WAIT
tcp_tw_recycle和tcp_timestamps導致connect失敗問題
tcp短連接TIME_WAIT問題解決方法大全(1)- 高屋建瓴
tcp短連接TIME_WAIT問題解決方法大全(2)- SO_LINGER
tcp短連接TIME_WAIT問題解決方法大全(3)- tcp_tw_recycle
tcp短連接TIME_WAIT問題解決方法大全(4)- tcp_tw_reuse
tcp短連接TIME_WAIT問題解決方法大全(5)- tcp_max_tw_buckets
TCP的TIME_WAIT快速回收與重用
淺談CLOSE_WAIT
又見CLOSE_WAIT
PHP升級導致系統負載過高問題分析
Coping with the TCP TIME-WAIT state on busy Linux servers
❹ Linux上TCP的幾個內核參數調優
Linux作為強大操作系統提供了豐富的內核參數進行調優,TCP內核參數調優尤其重要。本文聚焦於內網環境下的TCP參數調優,分享一些實踐經驗。
調優清單包括:tcp_max_syn_backlog、somaxconn、tcp_abort_on_overflow。這三個參數關聯內核TCP連接緩沖隊列,設定過小可能導致連接被無端丟棄,引起詭異現象,建議增大Backlog隊列大小以避免問題。
設置tcp_abort_on_overflow可避免連接被意外丟棄。同時,確保Java應用正確配置Backlog參數,避免默認值過小導致連接問題。
考慮tcp_tw_recycle參數可能帶來的負面影響,如NAT環境下連接成功率降低。高版本內核已優化此參數,如遇TIME_WAIT問題,調整相關參數可緩解。
優化tcp_syn_retries參數,設置合適的重傳次數以改善連接建立時的超時時間。Java應用通常可通過API設置超時時間,降低依賴於內核參數的重要性。
調整tcp_retries2參數,用於計算傳輸過程中的重傳次數,對特定場景如長ReadTimeout設置有顯著影響。優化此參數可減少宕機時的響應延遲,但資源隔離策略也是關鍵。
在物理機宕機與進程宕機情形下,內核行為存在差異。物理機宕機會導致內核發送reset,減輕線程阻塞問題。
考慮tcp_slow_start_after_idle參數,Linux默認開啟。關閉此參數可提高某些請求的傳輸速度,適用於網路條件變化頻繁的場景。在內網系統間調用中,通常無需啟用此功能。
初始CWND大小對請求速率有顯著影響。Linux 2.6.32及以前版本初始CWND為(2-4)個mss,現代版本調整為RFC 6928推薦的10段,即14K左右,更適合內網環境。
總之,Linux內核提供豐富參數供調優,選擇最適合當前環境的組合至關重要。潛心研究,找到最佳實踐,可顯著提升系統性能。