TCP協議之網路延時
影響TCP 網路時延的因素
- 硬體速度
- 網路和伺服器的負載
- 請求和響應報文的尺寸
- 客戶端和伺服器之間的距離
- TCP 協議的技術複雜性
TCP協議產生的時延
- TCP 連線建立握手;
- TCP 慢啟動擁塞控制;
- 資料聚集的 Nagle 演算法;
- 用於捎帶確認的 TCP 延遲確認演算法;
- TIME_WAIT 時延和埠耗盡。
TCP連線建立
TCP連線的建立,需要經歷3個報文的互動過程,溝通相關連線引數,這個過程稱為三次握手(three-way handshake)。
因此,如果在每次傳送資料之前,都重新建立一次TCP連線,那麼建立連線的耗時將對效能產生較大的影響(特別是在傳送少量資料的情況下)。
優化方法
建立長連線,多次資料的傳送複用同一條連線。
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狀態的套接字更快的回收。
對於該設定,通常由專業運維同事在伺服器上做好相關配置。
關於TIME_WAIT問題,更詳細介紹可閱讀耗子叔的這篇文章《TCP 的那些事兒(上)》:
參考
《TCP/IP詳解卷1: 協議》
《HTTP權威指南》
維基百科
個人公眾號
更多文章,請關注公眾號:二進位制之路