納格算法

納格演算法是以減少封包傳送量來增進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頁面存檔備份,存於網際網路檔案館))


外部連結