ネットワークパフォーマンスとチューニング

このページの目次

ネットワークチューニングでは、意味のあるワークロードとユーザーの待ち時間を同時に最適化する必要があります。単に速度テストの数値を高めるだけではありません。まず目標を定義します:大容量ファイルの有効スループット、短リクエストの P99、接続確立レート、それとも小包転送 PPS か。目標によって、異なるバッチ、キュー、および並列化戦略が必要になる場合があります。

指標必須の口径
スループットアプリケーションペイロード、IP バイト数、リンク速度。単方向か双方向か
レイテンシアイドル/負荷状態、接続の再利用有無、P50/P95/P99 およびエラー率
PPSパケット長、レイヤー2オーバーヘッド、プロトコル、転送/暗号化の通過有無
CPU単一コアおよびキュー分布、ソフト割り込み、ユーザーモードおよびカーネルモード
リソース並列接続、バッファ、キュー、メモリ圧力およびドロップカウント
送信パス:容量、輻輳制御、キューイングは異なる制約です アプリケーション供給 生成、暗号化、バッチ処理、並列化 TCP ソケット バッファ、受信ウィンドウ、cwnd qdisc / pacing スケジューリング、シェーピング、AQM ドライバ / NIC キュー、セグメンテーション、DMA パスのボトルネック 競合フロー、容量、ディープキュー 受信アプリケーション 処理能力、逆方向 ACK cwnd は送信許可であり、独立した FIFO ではありません。パス上のどこでも有効スループットを制限する可能性があります。

ボトルネックがどの制約に属するかをまず確認する

帯域幅が最大限に活用されない理由は、単一フローのウィンドウ、輻輳、アプリケーション供給、CPU、暗号化、ストレージ、レート制限、または受信処理など多岐にわたります。cwnd が小さいからといって、ソケットバッファが小さいことを自動的に証明するものではありません。送信アプリケーションがデータを継続的に供給していない場合、ウィンドウを拡大しても負荷は発生しません。

観察次の検証ステップ安易に導き出すべきでない結論
単一フローは遅いが、複数フローは速い単一フローのウィンドウ、CPU/キュー、レート制限、パスハッシュ複数フローですべてのパフォーマンス問題が解決されたわけではない
送信キューに未送信データが長期間蓄積されている受信ウィンドウ、輻輳許可、pacing、アプリケーションバックプレッシャーsend buffer を増やすだけでよいわけではない
負荷上昇時に RTT が大幅に増加キュー、無線競合、CPU スケジューリング、受信処理必ずしもルーターの bufferbloat が原因ではない
特定コアが満杯だが、全体平均は低いRSS/IRQ/アプリケーションスレッド、NUMACPU がボトルネックではない
受信側で ZeroWindowアプリケーションの読み取り速度、バッファ解放速度送信側で輻輳アルゴリズムを変更すれば解決するわけではない

BDP:必要な在途量を推定する

帯域幅遅延積 BDP = 速度 × RTT は、その速度で継続的に送信する場合、往復待ち時間をカバーするために必要な在途データ量を表します。これは容量計画の起点ですが、各ソケットにメモリを事前に割り当てる指示ではありません。

目標速度と RTTBDP(10進数)約二分法容量
1 Gbit/s、30 ms3.75 MB3.58 MiB
1 Gbit/s、150 ms18.75 MB17.88 MiB
10 Gbit/s、200 ms250 MB238.42 MiB

cwnd、受信ウィンドウ、および在途データをバイト単位で統一すると、固定ウィンドウに対する速度の上限を推定できます。例えば、利用可能なウィンドウが 1 MiB、RTT が 100 ms の場合、パケットロスがなくても理想的な上限は約 83.9 Mbit/s に過ぎません。スロースタート、pacing、アプリケーション供給などはさらに結果に影響します。ss の cwnd はセグメント数で表示されることが多く、MSS を組み合わせて初めてバイト単位のバッファと比較できます。

from fractions import Fraction as F
bdp = 1_000_000_000 * F(30, 1000) / 8
assert bdp == 3_750_000
window_limit = 1_048_576 * 8 / F(100, 1000)
assert window_limit == F(83_886_080)
queue_ms = 4_000_000 * 8 / F(100_000_000) * 1000
assert queue_ms == 320
print('BDP 3.75 MB;1 MiB ウィンドウ上限 83.88608 Mbit/s;キュー遅延 320 ms')
同じ 4 MB の増加:在途データとしての意味とボトルネック前のキューとしての意味は異なる 1 Gbit/s × 30 ms RTT → BDP = 3.75 MB 十分な在途枠があれば往復待ち時間をカバーできますが、継続的な供給と利用可能な容量が必要です 100 Mbit/s 出口前のキュー 4 MB → キュー約 320 ms バッファは出口のサービス速度を増加させません。継続的な過剰入力は最終的に速度低下またはドロップを招きます BDP 推定には適切なベースライン RTT を使用します。膨張した RTT をさらに拡大の根拠にすると、キューが拡大します。

すでに深刻なキューを含んでいる RTT を使用してバッファを拡大すると、キューを「継続して埋める必要があるパイプライン」として扱ってしまいます。ベースライン/最小 RTT と実際の競合条件を組み合わせるべきであり、常に最大 RTT に帯域幅を掛けるべきではありません。

さらなる在途量は、いつ単にキューを増やすだけになるのか?

デフォルトの 1 Gbit/s、30 ms では、3.75 MB がベースライン BDP をちょうどカバーします。在途予算をさらに増やすと、キューは長くなりますが、スループットの上限は向上しません。BDP 以下に減らすと、キューは消滅し、ウィンドウがスループットを制限し始めます。

図を準備しています
さらなる在途量は、いつ単にキューを増やすだけになるのか?

ベースライン BDP に達した後、追加の継続的な在途量は、この単一ボトルネックモデルでキューを形成し、出口速度を超えることはできません。キュー RTT を使用して予算をさらに拡大すると、自分が作り出した待ち時間を追いかけることになります。

Linux バッファ:上限、実際の割り当て、通告ウィンドウは異なる

tcp_rmem と tcp_wmem の 3 つの値は、min/default/max の関連メモリポリシーを記述しています。受信の自動調整は、tcp_moderate_rcvbuf などの条件によっても影響を受けます。アプリケーションが SO_RCVBUF/SO_SNDBUF を明示的に設定すると、対応する自動調整動作が変更され、カーネルが依然として完全に自動上限に従って成長すると同時に仮定することはできません。

# 現在の設定のみを読み取り、現在のマシンとネームスペースの実際の値を確認する。
sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem \
  net.ipv4.tcp_moderate_rcvbuf net.core.rmem_max net.core.wmem_max
ss -tinm

カーネルのデフォルト値はバージョンやメモリに応じて変化することがあり、ディストリビューションが上書きすることもあります。「Linux のデフォルト受信最大は約 6 MB」としてすべてのマシンを判断することはできません。Linux 7.2 のドキュメントは、自動調整上限と手動ソケットオプションを明確に区別しています。tcp_wmem の自動最大値も net.core.wmem_max を上書きしません。Linux IP Sysctl

Linux は SO_RCVBUF/SO_SNDBUF パラメータの内部会計に追加スペースを含んでおり、getsockopt は倍増した値を返すことがよくあります。ソケットメモリ使用量、データペイロード、TCP 通告ウィンドウは同じ数字と見なすべきではありません。socket(7)

受信上限を 64 MiB に変更しても、各接続がすぐに 64 MiB を占有するわけではありません。しかし、10,000 のアクティブ接続が平均して実際に 4 MiB を占有する場合、この種のメモリだけで約 39.1 GiB になり、他のバッファやメタデータは含まれません。上限を上げる際は、並列数、メモリ圧力、および元の制限に実際に達しているかどうかを同時に評価する必要があります。

キュー管理:ボトルネックまで制御してこそ意味がある

キューは短いバーストを吸収しますが、待ち時間も増加させます。100 Mbit/s 出口前の 4 MB のキューは、約 320 ms の直列化待ち時間を増加させます。キューをどれだけ拡大しても、出口が 1 Gbit/s になるわけではありません。入力が出力を超えて継続する場合、輻輳フィードバック、シェーピング、またはビジネスバックプレッシャーが必要です。

CoDel は、パケットがキュー中に滞在している時間を観察し、最小滞在時間が interval 内で target を継続的に超えているかどうかを判断して、永続的なキューを識別します。任意のパケットがデフォルトの 5 ms を超えたからといって、すぐにドロップされるわけではありません。シグナルはドロップ也可以是、適用可能な条件下では ECN マークを使用できます。CoDel

FQ-CoDel は、フローをキューに振り分け、スケジューリングし、CoDel と組み合わせて各キュー内の永続的な待ち時間を制御します。インタラクティブフローとバーストフローの共存を改善できますが、ハッシュ分類、異なるフロー数、実装条件により、「絶対的な公平性、飢餓の永不発生」は一般的な保証ではありません。FQ-CoDel

CAKE は、シェーピング、キュー管理、フロー/ホスト分離、DiffServ などのメカニズムを組み合わせます。単に fq_codel の名前を変更したものではなく、すべてのインターフェースで必然的に最適也不是ありません。シェーピング速度、リンク層オーバーヘッド、実際のボトルネックは一致している必要があります。下行では、適切な ingress/転送パスで制御を実施できる必要があります。tc-cake

シナリオなぜローカルで qdisc を変更しても無効なのか
1 Gbit/s NIC の後に 100 Mbit/s の制御不能なデバイスが接続されているローカルからの送信が速すぎるため、深いキューは下流に残る
外部の複数のホストが出口を共有しているローカルではすべての競合トラフィックが見えない
実際の上り速度は 100 Mbit/s だが、950 Mbit/s でシェーピングしているボトルネックを制御可能な位置に移動していない
無線容量が急速に変化している固定のシェーピング値が即時容量と一致しない可能性がある

まず tc -s qdisc show dev eth0 で既存の構造を観察し、どこでスケジューリングまたはシェーピングを行うかを決定します。root qdisc の変更は既存のビジネスポリシーを置き換える可能性があり、操作前に既存の設定を記録し理解する必要があります。チューニング記事は、すべてのマシンに replace コマンドをそのまま適用すべきではありません。

CUBIC、BBR、pacing:アルゴリズム名はパフォーマンス結論ではない

CUBIC は、輻輳イベントとウィンドウ成長関数に基づいて送信許可を調整します。RFC 9438 で記述されているのは CUBIC であり、BBR ではありません⁠。BBR は、配信速度、RTT などを基にパスモデルを構築し、pacing/inflight を制御します。異なる世代のパケットロス、ECN、プロービング動作は異なります。CUBIC RFC 9438、BBR 公式プロジェクト

BBR の起動と帯域幅プロービングはキューを生成する可能性があり、常に CUBIC より優れているとは限りません。正確なカーネル/パッチバージョン、競合フロー、RTT、パケットロスの発生元、および測定目標を報告する必要があります。ローカルで bbr と呼ばれるモジュールが、自動的に Google リポジトリの最新世代がデプロイされていることを意味するわけではありません。

sysctl net.ipv4.tcp_available_congestion_control \
  net.ipv4.tcp_congestion_control
tc -s qdisc show dev eth0

グローバルデフォルトの輻輳アルゴリズムは、後続の対応する接続に主に影響します。アプリケーションもソケットごとにアルゴリズムを選択する可能性があります。sysctl を一度変更しただけでは、すべての既存接続が切り替わったことを証明するものではありません。送信 pacing は qdisc/カーネル実装と協力して動作し、fq、fq_codel、cake は同じメカニズムではありません。名前に fq が含まれているからといって、機能が完全に同じであると考えることはできません。tc-fq

小包:まず PPS を計算し、CPU 分布を確認する

理想的な 10 Gbit/s Ethernet の最小フレーム線速は、64 B フレーム(FCS 含む)、8 B プリアンブル/SFD、12 B フレームギャップで計算され、フレームあたり 84 B の時間を要し、約 14.88 Mpps になります。これは、「10 Gbit/s の大容量ファイルダウンロード」が CPU に与える圧力とは全く異なります。

from fractions import Fraction as F
small_pps = F(10_000_000_000, (64 + 8 + 12) * 8)
large_pps = F(10_000_000_000, (1518 + 8 + 12) * 8)
assert 14_880_000 < small_pps < 14_890_000
assert 812_000 < large_pps < 813_000
assert 18 < small_pps / large_pps < 19
assert F(10_000 * 4 * 1024**2, 1024**3) == F(625, 16)
print('理想的最小フレーム 14.88 Mpps、1518 B フレーム 0.813 Mpps、平均バッファ約 39.06 GiB')

この計算は、より上位の物理エンコーディングなどの他の速度口径の違いを無視しており、現在のホストがその PPS を達成できることを意味するものではありません。高いパケット速度では、各パケットが独立した割り込みをトリガーすると仮定すべきではありません。NAPI、割り込み結合、バッチ処理は CPU コストを変更します。

メカニズム主な役割トレードオフ
TSOハードウェアで TCP セグメンテーションを実行ソフトウェアの逐次セグメント作業を減らす。ハードウェアとメッセージ条件に制約される
GSOソフトウェアスタックでセグメンテーションを遅延させるすべての作業を NIC に移すわけではない
GRO受信パスで適用可能なメッセージを結合する上位層の処理粒度とパケットキャプチャの観察形態を変更する
RSSハードウェアでフローを受信キューに分散ハッシュ単一フローは通常 1 つのキューにマッピングされ、順序入れ替えを避ける
RPS/RFS/XPSソフトウェア CPU/キュー選択と局所性最適化コア間転送が増加する可能性があり、コア数が多いほど良いわけではない
Ring / 割り込み結合バーストをバッファリングし、割り込み頻度を減少させるより深いバッファまたはより多くの結合は待ち時間を増加させる可能性がある

CPU、IRQ、キュー、NUMA 位置に基づいて負荷を確認することは、まずすべての ring を最大値に設定するよりも意味があることが一般的です。オフロードの問題も、まずパケットキャプチャ位置とドライバ統計と照らし合わせるべきです。オフロードを無効にすると CPU とスループットが変化するため、明確な仮定の下での対照として扱う必要があります。Linux Scaling、Segmentation Offloads

一般的なパラメータはどのような証拠に対応すべきか

パラメータまたはメカニズム適切な調査エントリポイント代替できないもの
somaxconn / listen backlogaccept キューの蓄積、オーバーフロー、アプリケーションの accept 速度実際のビジネス処理能力の増加
tcp_max_syn_backlog未完成のハンドシェイクキューの圧力と関連カウント完了済みキューと混同すること
TCP_NOTSENT_LOWAT未送信データが多すぎる場合、アプリケーションの書き込み通知とバックプレッシャーオンラインの在途バイト数の正確な制限
TCP Fast OpenTFO をサポートするアプリケーション、ハンドシェイクコスト、リプレイセマンティクスtcp_fastopen=3 を変更しただけですべてのアプリケーションが有効になるわけではない
tcp_tw_reuse実際のソースポート/接続再利用のニーズとプロトコル条件TIME_WAIT が少ないほど良いわけではない

Linux 7.2 の tcp_tw_reuse は、0(無効)、1(グローバル有効)、2(loopback のみ)を区別しており、「1 を設定、クライアント側で安全」という結論だけを導き出すことはできません。まず接続の再利用、宛先分布、ソースポートの制約、ビジネスライフサイクルを確認します。大量の TIME_WAIT を削除することが最適化目標ではありません。Linux IP Sysctl パラメータ

テストが具体的な質問に答えるようにする

以下のコマンドは、認可されたテストサービス環境で使用するためのものです。iperf3 のサーバーは、テスト双方が事前に準備する必要があります。

# クライアントからサーバーへ送信、単一フロー。
iperf3 -c perf.example -t 30 -P 1 -J

# 逆方向:サーバーからクライアントへ送信。同時に双方向を測定するものではない。
iperf3 -c perf.example -t 30 -P 1 -R -J

# 複数フローの対照。単一フローの結果と混ぜて一つの数字にしてはならない。
iperf3 -c perf.example -t 30 -P 4 -J

-R は方向のみを反転させます。同時双方向は別のテスト条件です。iperf3 が測定するのは、ツールとエンドポイントがその条件下でのスループットであり、CPU、カーネル、ソケットから切り離された「裸のネットワーク帯域幅」ではありません。UDP テストの送信目標速度、受信側の goodput、損失、順序入れ替えもそれぞれ報告する必要があります。iperf3 公式マニュアル

1 回の対照では、少なくともテストバージョン、方向、フロー数、継続時間、パケット長またはブロックサイズ、両端の CPU、スループット、負荷下の RTT/テールレイテンシ、エラー率を記録します。外部負荷の変化による誤解を避けるため、ベースラインと候補設定を交互に実行できます。スループットが 5% 向上したが、P99 が 2 倍になったりエラー率が上昇したりした場合、結果は元の目標に基づいて評価すべきであり、最も速い一度だけの結果を報告してはいけません。

具体的な証拠の収集については tcpdump と Wireshark を参照し、フェーズの特定については ネットワークトラブルシューティング方法論 を参照してください。変更のすべては、観察された制限に対応でき、同じワークロードで改善と代償を検証する必要があります。

測定から待ち行列モデルへ

スループット上限に近づくと遅延が急増する場合、測定とシミュレーションで要求の定義、並行実行モデル、観測区間を固定し、Littleの法則で平均系内数、スループット、平均滞在時間を照合します。平均の関係だけではp99は分かりません。処理時間、待ち時間、負荷生成方法の変化を分けてください。