TCP協議之網絡延時


影響TCP 網絡時延的因素
硬件速度
網絡和服務器的負載
請求和響應報文的尺寸
客戶端和服務器之間的距離
TCP 協議的技術復雜性
TCP協議產生的時延
TCP 連接建立握手;
TCP 慢啟動擁塞控制;
數據聚集的 Nagle 算法;
用於捎帶確認的 TCP 延遲確認算法;
TIME_WAIT 時延和端口耗盡。
TCP連接建立
TCP連接的建立,需要經歷3個報文的交互過程,溝通相關連接參數,這個過程稱為三次握手(three-way handshake)。

因此,如果在每次發送數據之前,都重新建立一次TCP連接,那么建立連接的耗時將對性能產生較大的影響(特別是在發送少量數據的情況下)。

 

三次握手四次揮手(參考自coolshell)

優化方法

建立長連接,多次數據的發送復用同一條連接。

TCP慢啟動
如果在發送方和接收方之間存在多個路由器和速率較慢的鏈路,此時多個發送方一開始便向網絡發送多個報文段,由於受網絡傳輸和服務端處理能力的影響,一些中間路由器必須緩存分組,並有可能最終耗盡存儲器的空間,因而更多的報文發送將使網絡出現擁塞。

TCP慢啟動(slow start),就是用於防止因特網的突然過載和擁塞的一種流量控制機制。

慢啟動為發送方的TCP增加了一個窗口:擁塞窗口(congestion window),簡稱cwnd。

剛建立連接時,擁塞窗口被初始化為1個報文段。每收到一個ACK,擁塞窗口就增加一個報文段。發送方取擁塞窗口與接收方通告窗口中的最小值作為發送上限。

也就是說,TCP連接會隨着時間進行自我“調諧”,起初會限制連接的最大速度,如果數據成功傳輸,會隨着時間的推移提高傳輸的速度。

注:擁塞窗口是發送方使用的流量控制,而通告窗口則是接收方使用的流量控制。(和滑動窗口一樣么?)

優化方法

采用長連接,避免每次建立連接后的慢啟動。

Nagle算法
在廣域網上,小分組會增加網絡擁塞出現的可能性。Nagle算法(根據其發明者John Nagle命名)旨在收集這些小分組,以一個分組的方式發出去,以提高網絡效率。

該算法要求一個TCP連接上最多只能有一個未被確認的未完成的小分組,在該分組的確認到達之前不能發送其他的小分組。

該算法的優越之處在於它是自適應的:確認到達得越快,數據也就發送得越快。

Nagle 算法會引發以下性能問題

當報文無法填滿一個分組時,需要等待其他額外數據;
Nagle算法會阻止數據的發送,直到有確認分組抵達為止,但確認分組自身會被延遲確認算法延遲 100 ~ 200 毫秒。
算法偽代碼

if there is new data to send
  if the window size >= MSS and available data is >= MSS
    send complete MSS segment now
  else
    if there is unconfirmed data still in the pipe
      enqueue data in the buffer until an acknowledge is received
    else
      send data immediately
    end if
  end if
end if
優化方法

對於實時性要求較高的應用場景,可以通過設置TCP_NODELAY參數來關閉Nagle算法,提高性能。

延時確認算法
通常TCP在接收到數據時並不立即發送ACK;相反,它推遲發送,以便將ACK與需要沿該方向發送的數據一起發送。

有時稱這種現象為數據捎帶ACK,由於確認報文通常很小,所以TCP允許在發往相同方向的輸出數據分組中對其進行“捎帶”。

絕大多數實現采用的時延為200ms,也就是說,TCP將以最大200ms的時延等待是否有數據一起發送。

通常,延遲確認算法會引入相當大的時延。

優化方法

根據所使用操作系統的不同,可以調整或禁止延遲確認算法。(這個方法我沒嘗試過)

TIME_WAIT狀態
TIME_WAIT狀態也稱為2MSL等待狀態。

當某個 TCP 端點關閉 TCP 連接時, 會在內存中維護一個小的控制塊,用來記錄最近所關閉連接的 IP 地址和端口號。

這類信息只會維持一小段時間,通常是所估計的報文段最大生存時間的的兩倍(稱為2MSL,通常為2分鍾左右),以確保在這段時間內不會創建具有相同地址和端口號的新連接。

實際上,這個算法可以防止在兩分鍾內創建、關閉並重新創建兩個具有相同IP地址和端口號的連接。

將 2MSL 的值取為 2 分鍾是有歷史原因的。很早以前,路由器的速度還很慢,人們估計,在將一個分組的復制副本丟棄之前,它可以在因特網隊列中保留最多一分鍾的時間。現在,最大分段生存期要小得多了。

報文段最大生存時間MSL(Maximum Segment Lifetime),是指任何報文段被丟棄前在網絡中的最長生存時間。

RFC 793 [Postel 1981c]指出MSL為2分鍾。然而,實現中的常用值是30秒,1分鍾或2分鍾。

優化方法

打開tcp_tw_reuse,讓程序可以重用處於TIME_WAIT狀態的端口。如果使用tcp_tw_reuse,必需設置tcp_timestamps=1(默認值)。(這個對於快速重啟某些服務很有用,特別是服務端程序)
打開tcp_tw_recycle,讓處於TIME_WAIT狀態的套接字更快的回收。

貼一個nagle算法更詳細的講解

Nagle算法用於對緩沖區內的一定數量的消息進行自動連接。該處理過程(稱為Nagling),通過減少必須發送的封包的數量,提高了網絡應用程序系統的效率。

1. Nagle算法的規則

  (可參考tcp_output.c文件里tcp_nagle_check函數注釋):
1)如果包長度達到MSS(MSS是最大分段大小Maxitum Segment Size ,MTU是最大傳輸單元Maxitum Transmission Unit),則允許發送;
2)如果該包含有FIN,則允許發送;
3)設置了TCP_NODELAY選項,則允許發送;
4)未設置TCP_CORK選項時,若所有發出去的包均被確認,或所有發出去的小數據包(包長度小於MSS)均被確認,則允許發送。
   對於規則4),就是說一個TCP連接上最多只能有一個未被確認的小數據包,在該分組的確認到達之前,不能發送其他的小數據包。如果某個小分組的確認被延遲了,那么后續小分組的發送就會相應的延遲。也就是說延遲確認影響的並不只是被延遲確認的那個數據包,而是后續所有的應答包。

2. Nagle算法的門檻

   實際上Nagle算法並不是很復雜,他的主要職責是數據的累積,實際上有三個門檻:

1)緩沖區中的字節數達到了一定量;

2)等待了一定的時間(一般的Nagle算法都是等待200ms);

3)緊急數據發送。

   這三個門檻的任何一個達到都必須發送數據了。一般情況下,如果數據流量很大,第二個條件是永遠不會起作用的,但當發送小的數據包時,第二個門檻就發揮作用了,防止數據被無限的緩存在緩沖區不是好事情哦。 

3. Nagle算法的選項配置

   TCP_NODELAY和TCP_CORK都是禁用Nagle算法,只不過NODELAY完全關閉而TCP_CORK完全由自己決定發送時機。Linux文檔上說兩者不要同時設置。

3.1 TCP_NODELAY 選項

設置該選項: setsockopt(s,IPPRO_TCP,TCP_NODELAY,(const char*)&on,sizeof(int));
讀取該選項: getsockopt(s,IPPRO_TCP,TCP_NODELAY,(char*)&on,&optlen);  

  

   默認情況下, 發送數據采用Nagle 算法. Nagle 算法是指發送方發送的數據不會立即發出,而是先放在緩沖區, 等緩存區滿了再發出. 發送完一批數據后, 會等待接收方對這批數據的回應,然后再發送下一批數據。 

   Nagle 算法適用於發送方需要發送大批量數據, 並且接收方會及時作出回應的場合, 這種算法通過減少傳輸數據的次數來提高通信效率。

   如果發送方持續地發送小批量的數據, 並且接收方不一定會立即發送響應數據, 那么Nagle算法會使發送方運行很慢。

3.2 TCP_CORK選項

   TCP鏈接的過程中,默認開啟Nagle算法,進行小包發送的優化。優化網絡傳輸,兼顧網絡延時和網絡擁塞。這個時候可以置位TCP_NODELAY關閉Nagle算法,有數據包的話直接發送保證網絡時效性。

   在進行大量數據發送的時候可以置位TCP_CORK關閉Nagle算法保證網絡利用性。盡可能的進行數據的組包,以最大mtu傳輸,如果發送的數據包大小過小則如果在0.6~0.8S范圍內都沒能組裝成一個MTU時,直接發送。如果發送的數據包大小足夠間隔在0.45內時,每次組裝一個MTU進行發送。如果間隔大於0.4~0.8S則,每過來一個數據包就直接發送。

   Nagle組織包的長度是由系統決定的,有時候我們知道我們會每個1分鍾產生1字節,共1000字節。如果完全由Nagle算法來發送的話,可能還是會1字節1字節發送[這是一種極端情況,假設返回ACK時間不是很長]。這個時候首先設置TCP_CORK能夠阻塞住TCP[盡量阻塞住],等我們write完1000字節之后,取消TCP_CORK,這個時候就能夠將1000字節一次發出。

總結:

   TCP_CORK選項與TCP_NODELAY一樣,是控制Nagle化的。      

1)打開TCP_NODELAY選項,則意味着無論數據包是多么的小,都立即發送(不考慮擁塞窗口)。
2)如果將TCP連接比喻為一個管道,那TCP_CORK選項的作用就像一個塞子。            

   設置TCP_CORK選項,就是用塞子塞住管道,而取消TCP_CORK選項,就是將塞子拔掉。            

   當TCP_CORK選項被設置時,TCP鏈接不會發送任何的小包,即只有當數據量達到MSS時,才會被發送。

   一般當數據傳輸完成時,通常需要取消該選項,以防被塞住,這樣才可以讓不夠MSS大小的包能及時發出去。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM