ネーグルのアルゴリズムは、ネットワーク上で送信する必要のあるパケット数を削減することで、TCP/IPネットワークの効率を向上させる手段です。これは、フォード・エアロスペース社に勤務していたジョン・ネーグルによって定義されました。1984年にRFC 896 「IP/TCPインターネットワークにおける輻輳制御」というタイトルでRFC( Request for Comments)として公開されました。
RFCでは、 Nagleが「小パケット問題」と呼ぶ現象について説明しています。これは、アプリケーションがデータを小さなチャンク(多くの場合、1バイト)で繰り返し送信する問題です。TCPパケットには40バイトのヘッダー(TCPの場合は20バイト、IPv4の場合は20バイト)があるため、1バイトの有用な情報に対して41バイトのパケットが生成され、大きなオーバーヘッドが発生します。この状況は、ほとんどのキー入力で1バイトのデータが即座に送信されるTelnetセッションでよく発生します。さらに悪いことに、低速なリンクでは、このようなパケットが同時に多数送信される可能性があり、輻輳崩壊につながる恐れがあります。
ネーグルのアルゴリズムは、複数の小さな送信メッセージをまとめて一度に送信することで機能します。具体的には、送信側が確認応答を受け取っていない送信済みパケットが存在する限り、送信側は完全なパケット分の出力が揃うまで出力をバッファリングし続け、それによって出力を一度にすべて送信できるようにします。
RFCでは、アルゴリズムを次のように定義しています。
接続上で以前に送信されたデータが未確認のまま残っている場合、ユーザーから新しい送信データが到着した際に、新しいTCPセグメントの送信を抑制します。
ここで、MSSは最大セグメントサイズ、つまりこの接続で送信できる最大のセグメントであり、ウィンドウサイズは現在許容される未確認データのウィンドウです。これは擬似コードで次のように記述できます。
送信する新しいデータがある場合、 ウィンドウサイズが MSS 以上で、利用可能なデータが MSS 以上であれば、 MSSセグメント全体を今すぐ送信 そうでなければ 、パイプラインに未確認データが残っている場合は 確認応答が受信されるまでバッファにデータをキューイングする それ以外 データを即座に送信する end if end if end if
このアルゴリズムは、 TCPの遅延確認応答(遅延ACK)と相性が悪い。遅延ACKは、1980年代初頭にほぼ同時期に、別のグループによってTCPに導入された機能である。両方のアルゴリズムが有効になっている場合、TCP接続に対して2回連続で書き込みを行い、その後、2回目の書き込みデータが宛先に到達するまで完了しない読み取りを行うアプリケーションでは、最大500ミリ秒の一定の遅延、すなわち「ACK遅延」が発生する。どちらか一方を無効にすることを推奨するが、リアルタイムアプリケーションでは既にNagleアルゴリズムを無効にするスイッチが用意されているため、従来はNagleアルゴリズムを無効にする方が容易であった。
ネーグルが推奨する、アルゴリズムが時期尚早にパケットを送信するのを防ぐ解決策は、アプリケーションの書き込みをバッファリングしてからバッファをフラッシュすることです。[ 1 ]
ユーザーレベルの解決策は、ソケット上で書き込み→書き込み→読み込みのシーケンスを避けることです。書き込み→読み込み→書き込み→読み込みは問題ありません。書き込み→書き込み→書き込みも問題ありません。しかし、書き込み→書き込み→読み込みは致命的です。したがって、可能であれば、TCPへの小さな書き込みをバッファリングして、一度にすべて送信してください。標準のUNIX I/Oパッケージを使用し、読み込みの前に書き込みをフラッシュすると、通常はうまくいきます。
Nagle は、遅延 ACK は「悪い考え」だと考えている。なぜなら、アプリケーション層は通常、遅延ウィンドウ内に応答しないからである (遅延ウィンドウ内に応答すると、ACK を応答パケットと組み合わせることが可能になる)。[ 2 ]一般的な (非リアルタイム) ユースケースでは、彼のアルゴリズムを無効にするのではなく、遅延 ACK を無効にすることを推奨している。なぜなら、「クイック」 ACK は、同じラウンドトリップ時間の改善に対して、多数の小さなパケットほどオーバーヘッドを生じさせないからである。[ 3 ]
TCP の実装では、通常、アプリケーションに Nagle アルゴリズムを無効にするためのインターフェイスが提供されます。これは通常、TCP_NODELAYオプションと呼ばれます。Microsoft Windowsでは、レジストリTcpNoDelayスイッチによってデフォルトが決定されます。TCP_NODELAYは、1983 年の 4.2BSD の TCP/IP スタック以来存在しており、多くの派生バージョンがあります。[ 4 ]
遅延ACKを無効にするためのインターフェースは、システムによって一貫性がありません。このTCP_QUICKACKフラグは、Linuxでは2001年(2.4.4)から利用可能で、Windowsでも利用可能になる可能性があり、Windowsの公式インターフェースは[ 5 ]SIO_TCP_SET_ACK_FREQUENCYです。
Windows レジストリTcpAckFrequencyで 1 に設定すると、デフォルトで遅延 ACK が無効になります。[ 6 ] FreeBSDでは、sysctlエントリnet.inet.tcp.delayed_ack がデフォルトの動作を制御します。[ 4 ] Linux にはそのようなスイッチはありません。[ 7 ]
遅延ACKとNagleの相互作用は、より大きな書き込みにも及ぶ。単一の書き込みのデータが2 nパケットにまたがる場合、2 n -1個の完全なTCPセグメントの後に部分的なTCPセグメントが続くとすると、元のNagleアルゴリズムは最後のパケットを保留し、送信するデータ(パケットを埋めるため)または前のパケットのACK(前のすべてのパケットがネットワークから送信されたことを示す)のいずれかを待つ。遅延ACKは、 最後のパケットが送信される前に最大500ミリ秒を追加する。[ 8 ]この動作は、永続接続を持つHTTPなどのパイプライン化されていないストップアンドウェイト要求応答アプリケーションプロトコルのパフォーマンスを制限する。[ 9 ]
MinshallによるNagleアルゴリズムの修正により、最後のパケットがフルサイズの場合は常に送信し、最後のパケットが部分的な場合にのみ確認応答を待つようになりました。この大きな書き込みのペナルティに対処することで、Nagleを無効にするインセンティブを弱めることが目的でした。[ 10 ]繰り返しますが、受信側で遅延ACKを無効にすれば、この問題は完全に解消されます。
リアルタイム応答と低遅延を期待するアプリケーションは、Nagle アルゴリズムにうまく対応できない場合があります。ネットワーク マルチプレイヤー ビデオ ゲームやリモート制御オペレーティングシステムでのマウスの動きなどのアプリケーションは、アクションが即座に送信されることを期待しますが、このアルゴリズムは意図的に送信を遅延させ、片方向の遅延を犠牲にして帯域幅の効率を高めます。[ 3 ]このため、低帯域幅で時間制約のある送信を行うアプリケーションは、通常、Nagle による ACK 遅延を回避するために を使用します。[ 11 ]TCP_NODELAY
別の選択肢としては、 UDPを使用する方法もあります。
ほとんどの最新のオペレーティングシステムは、Nagleのアルゴリズムを実装しています。AIX [ 12 ]とWindowsでは、デフォルトで有効になっており、オプションを使用してソケットごとに無効にすることができますTCP_NODELAY。
[...] Nagleアルゴリズムを無効にする正当なケースは、ネット上で動作するFPSゲームくらいしかない。そこでは、片方向の遅延が重要になる。他のプレイヤーより先にサーバーにショットや動きを送ることがゲームプレイに影響する。