
2025/12/23 6:09
常に **TCP_NODELAY** になっています。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
概要:
この記事では、現代の分散システムにおいては
TCP_NODELAY を有効にする(すなわち Nagle のアルゴリズムを無効化する)ことが最良のプラクティスであると主張しています。現在、そのブロッキング動作は不要なレイテンシーだけを増やすだけになるためです。開発者はレイテンシーのデバッグ時にこのフラグを定期的に確認し、多くが単にオンにすることで数時間分の遅延を解消したと報告しています。Nagle は(RFC 896、1984)単一バイトパケットの 40 バイトヘッダーオーバーヘッドを削減するために導入されましたが、このアルゴリズムは前のパケットが ACK されるまで新しいデータをブロックし、ネットワーク RTT 以外のタイマーはありません。RFC 813 と RFC 1122 は ACK を遅延させる「遅延 ACK」を正式化し、追加のデータが到着するかタイマーが発火するまで ACK を保留します。これらを組み合わせると、パイプライン化されたレイテンシーセンシティブなトラフィックに対して停止(ストール)を引き起こします。Hacker News のコメントでは、「tinygram 防止」と固定タイマーが実際の原因であり、単なる遅延 ACK だけではないと指摘されています(Key Point 6)。現代のデータセンターでは、インデータセンターレイテンシー(約 500 µs)やリージョン間レイテンシー(数ミリ秒)が Nagle のブロッキングをレイテンシークリティカルなワークロードにとってコスト高にしています。さらに、現代のトラフィックは単一バイトパケットで構成されることがほとんどなく、TLS オーバーヘッドやシリアライゼーション、大きめのメッセージが Nagle の元々の動機をほぼ無意味にしています(Key Point 8)。著者はそのようなシステムでは TCP_NODELAY をデフォルトで有効にすることを推奨し、これを行うことは「罪」ではないと強調しています(Key Point 9)。
RFC 896 はまた、ネットワークが飽和状態になるとフェアなパケットドロップがネットワークを劣化させつつも安定に保つというメタステーブルな挙動についても触れています(Key Point 11)。最後に、著者はポータビリティの問題やプログラム制御を超えるカーネルバッファリング解決策がないため
TCP_QUICKACK を避けています(Key Point 12)。
要するに、現在のトラフィックパターンとハードウェア性能を考慮すると Nagle のアルゴリズムは必ずしも必要ではなく、
TCP_NODELAY を有効にすることがレイテンシーセンシティブなワークロードにおいて標準となるべきです。本文
それはもう1980年代ではないことに、幸いです。
分散システムでレイテンシ問題をデバッグするとき、最初に確認するのは TCP_NODELAY が有効になっているかどうかです。私だけではありません―知り合いのすべての分散システム開発者が、この単純なソケットオプションを有効にすることで素早く解決できるレイテンシ問題に何時間も費やした経験があります。デフォルト動作は誤っているようで、概念そのものが時代遅れになっているかもしれません。
ここでは何について語っていますか
1984年のジョン・ナゲ(John Nagle)によるRFC 896が最良の情報源です:
小さなパケットに関する特別な問題があります。キーボードから発信される単文字メッセージをTCPで送信するとき、典型的には 41バイト のパケット(1バイトデータ+40バイトヘッダー)が有用データ1バイトごとに送信されます。この4000 %のオーバーヘッドは軽負荷ネットワークでは許容範囲ですが、面倒です。
簡単に言えば、ナゲはTCPヘッダーコストをより良く分散しスループットを改善したい(最悪の場合で最大 40倍)という目的でした。小さなパケットの主な原因は次のとおりです:
- ユーザーが1バイトずつ入力する人間対話型アプリケーション(例:シェル)
- 多数の
呼び出しでメッセージを「滴下」してしまう不十分に実装されたプログラムwrite()
ナゲの提案は簡潔かつ賢明でした:
単純でエレガントな解決策が発見されました:
ユーザーから新しい送信データが到着したとき、以前に送信されたデータがまだ ACK されていない場合は、新しい TCP セグメントの送信を抑制する。
RFC 896 は往復時間(RTT)のみを使用し、別途タイマーは設定していません。
遅延ACKとの相互作用
ナゲのアルゴリズムはもう一つのTCP機能である 遅延ACK とうまく連携できません。遅延ACK のアイデアは、次のどちらかが起きるまで ACK を送信しないことです:
- 何らかのデータを返せる場合(例:telnet エコー)
- タイマーが切れたとき
RFC 813(1982)が最初に提案し、RFC 1122(1989)で正式化されました。
この相互作用は問題を引き起こします:ナゲは ACK を受信するまで新しいデータの送信をブロックしますが、遅延ACK はその ACK が応答準備できるまで遅らせます。パケットを満タンに保つには良いですが、レイテンシ感度の高いパイプライン型アプリケーションにはあまり向きません。
ナゲ自身もフラストレーションを表明しています:
「それはまだ悩みます。実際の問題は小さなグラム防止ではなく、ACK の遅延とそのばかげた固定タイマーです。」
ナゲは無害なのか?
遅延 ACK が無い場合でも、ナゲのアルゴリズムの挙動は現代の分散システムではおそらく望ましいものではありません。
- 単一データセンター内の RTT は通常約 500 µs
- 同じリージョン内のインターデータセンターレイテンシは数ミリ秒
- グローバルレベルでは数百ミリ秒に達することも
サーバーが数百マイクロ秒で実行できる作業量を考えると、1 RTT だけ遅延させてデータを送信するのは明らかに有益とは言えません。
元々の正当化――ヘッダーコストを分散し単バイトパケットで最大40倍のオーバーヘッドを回避する―は、今日ではほとんど無意味です。多くの分散データベースやシステムは単一バイトパケットを送信せず、TLS を使用し、効率的なエンコーディング/シリアライズを採用しています。小さなメッセージに関する懸念は、アプリケーション層で実質的に処理されています。
ナゲが必要か?
明白な結論:
現代のデータセンターハードウェア上でレイテンシ感度の高い分散システムを構築しているなら、躊躇なく TCP_NODELAY(ナゲアルゴリズムを無効化)を有効にしてください。 罪ではありません—ただ実行すれば良いです。
もっと議論を呼ぶ見解:
現代のトラフィックパターンとハードウェア性能を考えると、ナゲアルゴリズムはそもそも不要だと思われます。TCP_NODELAY をデフォルトにすべきです。 1 バイトずつ書くコードは遅くなるかもしれませんが、効率が重要ならばアプリケーションを修正する方が適切です。
フットノート
- RFC 896 はコンピュータネットワークにおけるメタスタブル動作について最も初期の記述の一つです:「この状態は安定している… ネットワークは減衰した状態で継続的に機能する。」
- TCP_QUICKACK に関する質問が多いですが、ポータビリティと奇妙な意味合い(man ページ参照)から私はほとんど使用しません。さらに重要なのは、TCP_QUICKACK はカーネルがデータを保持している傾向を解消しないことです。
を呼び出したら「今すぐ送信する」という意味合いがあるためです。write()