納格演算法

納格演算法是以減少封包傳送量來增進TCP/IP網路的效能。它由約翰·納格任職於Ford Aerospace英語Ford Aerospace時命名。

納格的檔案[注 1]描述了他所謂的「小封包問題」-某個應用程式不斷地送出小單位的資料,且某些常只佔1位元組大小。因為TCP封包具有40位元組的標頭資訊(TCP與IPv4各佔20位元組),這導致了41位元組大小的封包只有1位元組的可用資訊,造成龐大的浪費。這種狀況常常發生於Telnet工作階段-大部分的鍵盤操作會產生1位元組的資料並馬上送出。更糟的是,在慢速的網路連線下,這類的封包會大量地在同一時點傳輸,造成壅塞碰撞英語Congestion Collapse

納格演算法的工作方式是合併(coalescing)一定數量的輸出資料後一次送出。特別的是,只要有已送出的封包尚未確認,傳送者會持續緩衝封包,直到累積一定數量的資料才送出。

演算法

 if有新資料要傳送
   if訊窗大小>= MSS and可傳送的資料>= MSS
     立刻傳送完整MSS大小的segment
   else
    if管線中有尚未確認的資料
      在下一個確認(ACK)封包收到前,將資料排進緩衝區佇列
    else
      立即傳送資料  

MSS = 最大分段大小

該演算法與 TCP延遲確認 會有不好的相互作用,例如當程式傳送端進行兩次連續的小段寫再跟著讀時,接收端接收到第一次寫後因TCP延遲確認而等待第二次寫後一併傳送ACK,傳送端則因第二次寫資料長度小於MSS而等待第一次寫的ACK(如上演算法所示),最終將導致兩對端都進入等待直到ACK延遲逾時。因為這個原因,TCP實現通常為應用程式提供一個禁用Nagle演算法的介面(通常稱為TCP_NODELAY選項)。使用者級解決方案是避免通訊端上的 寫-寫-讀 序列。 寫-讀-讀 和 寫-寫-寫 都是沒問題的。但 寫-寫-讀 則是效能殺手。所以,如果可以的話,緩衝你對TCP的小段寫,然後一次傳送它們。在每次讀之前使用標準的UNIX I/O包並沖刷寫快取通常能起作用。

與延遲 ACK 的互動

該演算法與TCP 延遲確認(delayed ACK)的互動很糟糕,該功能在 1980 年代初大致同時引入 TCP,但由不同的組。啟用這兩種演算法後,對 TCP 連接執行兩次連續寫入,然後在第二次寫入的數據到達目的地後才會完成讀取的應用程式會經歷長達 500 毫秒的持續延遲,「確認延遲」。建議禁用其中任何一個,儘管傳統上禁用 Nagle 更容易,因為實時應用程式已經存在這樣的開關。

Nagle 推薦的解決方案是通過緩衝應用程式寫入然後重新整理緩衝區來避免演算法傳送過早的封包:

使用者級解決方案是避免通訊端上的寫-寫-讀序列。寫-讀-寫-讀沒問題。寫-寫-寫很好。但是寫-寫-讀是一個殺手。因此,如果可以的話,緩衝您對 TCP 的少量寫入並一次性傳送它們。使用標準 UNIX I/O 包並在每次讀取之前重新整理寫入通常是可行的。

Nagle 認為延遲 ACK 是一個「壞主意」,因為應用層通常不會在時間窗口內響應。對於典型用例,他建議禁用「延遲 ACK」而不是他的演算法,因為「快速」ACK 不會像許多小封包那樣產生那麼多開銷。

禁用 Nagle 或延遲 ACK

TCP 實現通常為應用程式提供一個介面來禁用 Nagle 演算法。這通常稱為TCP_NODELAY選項。在 Microsoft Windows 上,TcpNoDelay註冊表開關決定了默認值。TCP_NODELAY自 1983 年 4.2BSD 中的 TCP/IP 堆棧以來就存在,這是一個具有許多後代的堆棧。

系統間禁用延遲ACK的介面不一致。該TCP_QUICKACK標誌自 2001 年 (2.4.4) 起在 Linux 上可用,並且可能在官方介面為SIO_TCP_SET_ACK_FREQUENCY. 默認情況下,在 Windows 註冊表中設定TcpAckFrequency為 1 會關閉延遲 ACK。

注釋

  1. ^ Congestion Control in IP/TCP InternetworksRFC 896頁面存檔備份,存於網際網路檔案館))


外部連結