Linuxネットワーク性能: 説明する前に測定する
ラボの前提: 所有するUbuntu Server 24.04 LTSまたはRocky Linux 9ゲスト。ループバックの観測に上限を設けて実施します。
最終更新日: September 15, 2026
目的と前提条件
このワークブックでは、処理の遅さがアプリケーション、トランスポート、カーネル、経路のどこで発生しているかを調べます。 成果物は、再現可能な測定レポートです。複数の説明候補、反証となる観測結果、元に戻した記録を含めてください。 一定の遅延、スループット向上、ベンチマークスコアを約束するものではありません。
初級コースを終え、特にモニタリングのレッスンを完了してください。 ソケット/VFSから送信、受信、フックの配置まで、カーネルのネットワーキングスタックを読んでください。 次に、既存のHTTPヘルパーとソケット状態の解釈について、Linuxネットワーク診断を確認します。 プロトコル演習では、バイトストリームと証拠に関する用語を学びます。 既存のPodベンチマークガイドも後で読んでください。ループバックの数値はCNIベンチマークではありません。
Linuxのプロセス/ファイル操作、基本的なPython、TCPのシーケンス/ウィンドウ、bit・byte・秒を使った計算が必要です。 Cやドライバーの開発は任意の発展課題であり、上限を設けたPython演習の前提ではありません。 この章の執筆中にネットワーク/クラウド実験は実施していません。以下の基準は、後日、所有するゲストで実施するための手順です。
Bootlinと一次資料の読み方
Bootlin Linux networkingのトレーニングページは2026年9月15日に閲覧できました。 無償でダウンロードできるスライドとEspressoBinラボ手順は学習に役立ちます。 公開資料には、無料の講師サポート、同梱ボード、任意のハードウェアとの互換性保証は含まれません。
| 読む資料 | 必要な背景知識 | ここで答える問い |
|---|---|---|
| Bootlinのネットワークスタックとユーザー空間インターフェースの節 | Linux管理、ソケット、プロトコル階層 | アプリケーションのバイト列はどこでカーネルのキューに入るか |
| Bootlinのドライバー、NAPI、ハードウェアラボ | C、カーネル/モジュール開発、割り込み、DMA、ラボ用ボード/ツールチェーンの準備に関する十分な知識 | 実際のドライバーとNICが必要となる主張はどれか |
| カーネルNAPIドキュメント | 割り込みとポーリングの違い | どの処理が、どの予算/コンテキストでポーリングされるか |
| カーネルのスケーリングに関するドキュメント | CPUキューとフローハッシュ | RSSまたはRPSが処理CPUを選ぶか |
| セグメンテーションオフロード | MTU/MSSとパケット観測ポイント | キャプチャにはなぜ実際の線上より大きな単位が見えることがあるか |
| TCP sysctlドキュメント | ソケットメモリ、ウィンドウ、自動調整 | どの上限がポリシーで、どれがフロー単位の観測値か |
| iproute2のssソースマニュアルとtcソースマニュアル | TCP状態とキューカウンター | 表示された各値が正確に何を数えているか |
Bootlinのハードウェア課程を行う場合は、ラボPDFのリビジョン、必要なボード、シリアルコンソール、ブートローダー、カーネルツリー/設定、クロスツールチェーンを記録します。 確認した課程ではMarvell Armada 3720 ARM64プロセッサ搭載のEspressoBinを使用します。初級編のVMが、この文書にある環境の代わりになるとは考えないでください。 その環境を用意できない場合はパケット経路の分析を完了し、ハードウェア観測は実施できなかったと記録します。 トレーニングの受講登録や修了証は、このワークブックの証拠に基づく完了条件とは別です。
コマンド実行前に測定を設計する
開始前に、次の実験カードを記入します。空欄は作業が残っている状態であり、結果を作ってよいという意味ではありません。
| 項目 | 基本演習での選択 |
|---|---|
| 仮説 | クライアントの本文読み取りを遅らせると、経路損失がなくてもアプリケーションの処理完了時間は延びる |
| リソース所有者/観測者 | 使い捨てゲスト1台の自分のユーザー。ゲスト名とネットワーク名前空間を記録する |
| クライアント/サーバー | PythonクライアントとリポジトリのHTTPヘルパー。127.0.0.1:18080だけを使用 |
| 変数 | 要求/エコー本文のサイズは64または4096 byte。クライアントの読み取り休止は0または0.15秒 |
| 固定する条件 | 一度に1件、要求ごとに新しいTCP接続、同じエンドポイント/ヘルパーを使用 |
| 実行量 | ウォームアップ1回と測定対象15回。各方向のペイロードは42 KiB未満 |
| 期限 | クライアント全体で60秒、ソケット操作のタイムアウト2秒、サーバー180秒 |
| 観測対象 | クライアントの単調時計による時間、範囲を限定したss、前後のインターフェース/qdiscカウンター |
| 失敗条件 | 内容/状態の失敗、想定外のリスナー、ツール不足、期限切れで停止 |
| 復旧 | 自分のクライアントを閉じ、自分のフォアグラウンドサーバーを停止し、リスナーが消えたことを確認 |
0.15秒の休止は入力パラメーターであり、測定したネットワーク遅延ではありません。 このワークロードは意図的に小さくしてあり、受信ウィンドウの枯渇やループバックの飽和を起こすものではありません。 このgoodputを使って、NICの処理能力、インターネット遅延、ルーティング収束を主張しないでください。 可能な範囲でゲストをアイドル状態にし、ほかのワークロードを記録してください。ループバックカウンターにはほかのプロセスの分も含まれます。
ツール、役割、実施範囲
不足パッケージ、トランザクションの事前確認、復旧記録について、初級編のゲストツール準備に従ってください。 所有するゲストに、選んだ経路で必要なツールだけをインストールします。ベースイメージに必ず含まれているとは限りません。
| ツール | Ubuntuの提供パッケージ | Rockyの提供パッケージ | 用途/権限 |
|---|---|---|---|
python3 3.9以降 | python3 | python3 | クライアント/サーバー、一般ユーザー |
ip、ss | iproute2 | iproute | 範囲を限定した観測、一般ユーザー |
tc | iproute2 | iproute-tc | qdiscカウンターの読み取り。環境によっては一般ユーザーで可 |
timeout、sha256sum | coreutils | coreutils | 実行を制限し、ヘルパーを識別する |
tcpdump | tcpdump | tcpdump | 任意のパケットキャプチャ。キャプチャ時のみsudoを使う |
ethtool | ethtool | ethtool | 既存NICの任意確認。一部の問い合わせでは権限が必要 |
pidstat | sysstat | sysstat | 任意のプロセスCPUサンプリング |
bpftool、bpftrace | カーネル/ディストリビューションに依存するパッケージ | カーネル/ディストリビューションに依存するパッケージ | 任意。提供元、カーネルサポート、認可を別途確認 |
任意項目を満たすためだけにカーネルパッケージをインストールしたり、トレース機能を有効にしたりしないでください。 BPFツールを使う場合は、インストール済みパッケージの所有者、ツール/カーネルのバージョン、BTFの有無、アクセスエラーを記録します。 コマンドが存在するだけでは、必要なBPF権限が使える証拠になりません。
ゲスト上でリポジトリのルートから実行します。
command -v python3 ip ss tc timeout sha256sum
python3 --version
uname -r
ip -Version
ss -V
tc -V
sha256sum examples/networking/foundations/http_lab.py
ss -ltn 'sport = :18080'リスナーフィルターで何らかのリスナーが見つかった場合は中止し、全箇所で一貫して別の未使用ポートを選んでください。無関係なサービスを停止してはいけません。 mkdir -m 700 linux-evidence-01で新しいプライベートディレクトリを作成します。すでに存在する場合は新しい名前を使ってください。 そのディレクトリにリポジトリのリビジョン、OSリリース、ツールのバージョン、名前空間、開始/終了時刻(UTC)を記録します。 以下のクライアント/サーバーコマンドはすべて、同じゲストと名前空間で一般ユーザーとして実行します。
処理経路をたどる
既存のカーネル章の図を使い、次の違いを書き加えます。 一般的なネイティブドライバーの受信経路は、NICキュー → NAPIポーリング → 任意のnative XDP → スタック/トランスポート → ソケット → アプリケーションです。 ドライバー/デバイスのオフロード方式とgeneric XDPは配置が異なります。すべてのフックを同じ位置に描かず、方式を明記してください。 送信処理はソケット/トランスポートからルーティングを通り、該当するキュー制御を経てデバイスへ進みます。
| 仕組み | 変更する内容 | 観測上の注意/反例 |
|---|---|---|
| NAPI | 多くの場合は割り込みと連携し、ポーリングでドライバーのイベントを処理する | ポーリング予算はアプリケーション遅延の保証ではない |
| RSS | ハードウェアがフローを受信キューに分散する | 1つのフローが1つのキューにハッシュされる場合があり、キューを増やしても各フローが分割されるとは限らない |
| RPS | ソフトウェアが受信処理を行うCPUを選択する | CPUへの分散は、NICがRSSを実行した証拠ではない |
| GSO/TSO | 大きな送信単位をソフトウェア/デバイスで分割する | ホスト側キャプチャの大きな単位が、実際の線上で過大なフレームとは限らない |
| GRO | 上位レイヤーの処理前に受信処理をまとめる | キャプチャで数えた単位数と物理フレーム数が一致するとは限らない |
| qdisc | 該当する送信処理をキューイング/スケジューリングする | ループバックのnoqueueは、別の場所にある物理NICのキューイングがない証拠ではない |
| ソケットウィンドウ | 受信側のフロー制御と送信側の輻輳制御上限 | バッファーの設定値が大きくても、どちらのウィンドウもすべて利用できているとは限らない |
ループバックには、性能評価の対象にする物理RSSキュー、リンク上のシリアライズ、スイッチ経路がありません。 その処理の詳細を物理ドライバーに当てはめないでください。
既存かつ所有するVM上のフローを調べる場合は、代わりに観測計画を記述します。両端、既存のインターフェース/経路、フロータプル、所有者、元のトラフィック上限を特定してください。 識別したラボ用インターフェースで対応している場合に限り、読み取り専用のethtool -k、ethtool -l、ethtool -x、ethtool -Sを使って観測します。 ドライバー、チャネル数、オフロードを変更せず、「未対応」または「権限がない」と記録します。 基本の経路確認に、範囲を指定しないインターフェース操作や、新しいVM/クラウドリソースは必要ありません。
上限を設定したループバック実験
ヘルパーを開始する前に、事前状態を保存します。
ip -s link show dev lo > linux-evidence-01/link-before.txt
tc -s qdisc show dev lo > linux-evidence-01/qdisc-before.txt
ss -ltn 'sport = :18080' > linux-evidence-01/listener-before.txtターミナルAで自分が所有するサーバーを起動し、準備完了メッセージを待ちます。
python3 examples/networking/foundations/http_lab.py --port 18080 --duration 180ターミナルCで、クライアントを起動する直前に、実行時間を制限したソケット観測を開始します。
timeout 25s bash -c '
for sample in {1..40}; do
date -u +%FT%T.%NZ
ss -tinm state established "( sport = :18080 or dport = :18080 )"
sleep 0.5
done
' > linux-evidence-01/sockets.txtターミナルBで、次の既存の測定クライアントを実行します。DNS問い合わせを行わず、プロキシ設定も読み取りません。 ウォームアップを含め、要求数の上限は16です。各接続はfinally節で閉じます。 要求間に0.25秒の休止を入れ、要求頻度にも上限を設けます。
timeout --signal=INT --kill-after=2s 60s python3 - <<'PY' \
> linux-evidence-01/transactions.jsonl
import datetime
import http.client
import json
import time
phases = [("warmup", 64, 0.0, 1),
("small", 64, 0.0, 5),
("large", 4096, 0.0, 5),
("reader_pause", 4096, 0.15, 5)]
for phase, size, pause, count in phases:
for sample in range(count):
connection = http.client.HTTPConnection("127.0.0.1", 18080, timeout=2)
payload = b"x" * size
row = {"phase": phase, "sample": sample, "bytes": size,
"pause_s": pause,
"utc": datetime.datetime.now(datetime.timezone.utc).isoformat()}
start = time.perf_counter()
try:
connection.request("POST", "/echo", body=payload,
headers={"Content-Type": "application/octet-stream"})
response = connection.getresponse()
headers_at = time.perf_counter()
time.sleep(pause)
body = response.read()
finished = time.perf_counter()
if response.status != 200 or body != payload:
raise ValueError("Unexpected status or echo content")
row.update(status=response.status, ok=True,
headers_ms=(headers_at - start) * 1000,
read_ms=(finished - headers_at) * 1000,
total_ms=(finished - start) * 1000)
except Exception as error:
row.update(ok=False, error=type(error).__name__,
detail=str(error))
print(json.dumps(row), flush=True)
raise SystemExit(1)
finally:
connection.close()
print(json.dumps(row), flush=True)
time.sleep(0.25)
PYクライアントの終了ステータスをすぐに保存してください。中断された実行、または成功行が16行未満の実行は未完了です。 外側のタイムアウトが発生すると、最後のJSON行が出力されないことがあります。データがないことは遅延ゼロを意味しません。 headers_msには、接続開始からレスポンスヘッダーの解析までの処理が含まれます。純粋なRTTでも、curlのTTFB指標でもありません。 read_msには意図的な休止と本文読み取りが含まれます。ライブラリがすでに一部の内容をバッファーに格納している場合があります。 total_msは、レスポンスを読み終えるまでを測定し、後続の要求との間に入る休止は含みません。
クライアントと観測処理が終了した後、事後状態を収集します。
ip -s link show dev lo > linux-evidence-01/link-after.txt
tc -s qdisc show dev lo > linux-evidence-01/qdisc-after.txt
ss -tinm state established '( sport = :18080 or dport = :18080 )' \
> linux-evidence-01/sockets-after.txt予想される観測結果: 完了したすべての要求で同じエコーバイト列が返ります。読み取り休止の段階では、完了時間に設定した休止時間が含まれるはずです。 否定的な観測結果: 接続時間が短いため、ssのサンプルが空になることがあります。キューが0でも、観測処理が壊れているとは限りません。 小さなエコーでは、明確なバックプレッシャーも再送も見えない場合があります。 カウンターの差分はループバックインターフェース全体を対象とするため、増分をすべてこのクライアントに帰属させないでください。 エコーが失敗した場合は、診断前に失敗した行とサーバーの状態を保存します。成功した結果だけが残るまで再試行してはいけません。
任意のパケット証拠が必要なら、新しい証跡ディレクトリで演習Bの上限付きキャプチャを使います。 その上限(20秒/120パケット)では、この実行の接続が一部しか記録されない場合があります。省略されたパケットを損失とみなさず、捕捉範囲が部分的であると記録してください。 キャプチャを見慣れた形にする目的で、チェックサム/セグメンテーションオフロードを無効にしないでください。
復旧: 自分がフォアグラウンドで起動したサーバーだけをCtrl+Cで停止するか、180秒の期限切れを待ちます。 クライアントと観測処理は設定した上限で終了します。必要な場合に限り、それらのフォアグラウンドプロセスに割り込みます。 ss -ltn 'sport = :18080'でリスナーが残っていないことを確認します。TIME_WAITソケットは残っていても問題ありません。 証跡ディレクトリを保存するか、レビュー後にそのディレクトリ内の指定ファイルだけを削除します。 この演習ではqdisc、sysctl、NICオフロード、経路、BPFアタッチメントを変更していません。
ウィンドウ、損失、遅延を解釈する
ソケットキューの意味と、ssの生サンプルを照合してください。 ESTABLISHED状態のRecv-Qは、受信済みでアプリケーションがまだ読み取っていないデータ量を示します。Send-Qは、まだ送信していないデータを含む未確認データ量です。 LISTEN状態の列はacceptキュー/バックログを示し、ペイロードの使用量ではありません。 skmemはメモリとオーバーヘッドを計上します。ストリームのバイト数、広告ウィンドウ、cwndと同じ値になるとは限りません。 cwndが表示される場合、通常はセグメント単位です。byte数と比較する前に、対応するMSSと単位を確認してください。
RTTが40 msの仮想的な100 Mbit/s経路を考えます。 BDP = 100,000,000 bit/s × 0.040 s ÷ 8 = 500,000 byteです。 これは計算例であり、測定値でも、バッファーを設定する指示でもありません。 BDPとソケットポリシーとの関係を考えてください。 有効なウィンドウが小さければスループットを制約する場合がありますが、グローバル上限を引き上げても、今回の遅延がウィンドウによるものだった証拠にはなりません。
ウォームアップを除外し、各段階について実際の行からサンプル数、失敗数、最小値、中央値、最大値を報告します。 5サンプルでは、信頼できるp99サービス目標や本番環境の容量を主張できません。 応答ペイロードのbit数を処理時間で割った値は、その操作におけるアプリケーションgoodputです。接続/処理時間も含まれます。 イーサネットのラインレートではなく、輻輳を直接測定する値でもありません。
| 観測結果 | 原因候補 | 代替説明を切り分けるために必要な証拠 |
|---|---|---|
| 完了時間が長いが、ヘッダー取得時間は通常 | クライアント側の読み取り遅延 | クライアント段階/タイムスタンプ。合計時間だけを根拠に経路の問題としない |
| 受信キューにデータが残り続ける | アプリケーションの読み取りが遅い、またはスケジューリングの問題 | 読み取りの進捗、CPUの証拠、同じフローの反復サンプル |
| 送信キューにデータが残り続ける | 未送信データ、ACK欠落、受信側の制限 | ウィンドウ/再送フィールドと両エンドポイントの証拠 |
| 再送が増える | 損失、並べ替え、または誤検知された再送 | シーケンス/タイミングの証拠。1つのカウンターだけでは破棄場所を特定できない |
| tcpdumpのキャプチャ破棄数が増える | 観測処理が追い付いていない | キャプチャ統計。TCP/経路上の損失と直接同じではない |
| qdiscの破棄数が増える | ローカルのキューポリシー/負荷 | 同じ時間帯/インターフェースでのトラフィックとの関連 |
eBPF/XDPによる観測と障害設計
ツールを選ぶ前に、カーネルBPFのドキュメントとBootlinのフックに関する説明を読みます。 すでに準備済みで、所有権と権限があるラボでは、bpftool prog showとbpftool net showを使って既存のプログラム/アタッチメントを一覧できます。 これらは読み取り専用の任意観測です。権限がなければ「観測できず」とし、「BPFなし」とはしません。 プログラムが存在するだけでは、このフローがそこで処理された証拠にも、スループットを改善した証拠にもなりません。
プログラムを読み込まずに、tracepointまたはkprobeを使う観測を1つ設計します。フック、タプル/名前空間のフィルター、フィールド、期間、イベント上限、オーバーヘッドの確認方法を明記してください。 必要なフィールドが存在するかは、そのカーネルのイベント形式/BTFで確認します。普遍的に使えるプローブ署名を作り上げないでください。 イベントの欠落をどう計上するか、クライアントサンプルのタイムスタンプとどう突き合わせるかを指定します。 tracepoint、TCプログラム、native XDPプログラムが観測する段階は異なります。1つのフックで観測できないからといって、どこにも存在しないとは限りません。 このワークブックではBPFプログラムをアタッチ、デタッチ、置き換えません。
任意のnetem拡張は、ここでは設計のみです。 ホスト全体に適用されるqdisc/sysctl/オフロードのコマンドは実行しないでください。 影響を受けるインターフェースの外に管理経路を確保できる、所有する専用名前空間/VMでの提案を記述します。 名前空間/VMの識別情報、インターフェース、元のqdisc階層/ハンドル/オプション、経路、オフロード、変更候補を記録します。 変数を1つに絞り、有限の正確なフロー/期間、ベースライン、予想される否定的な結果を定めてください。 実行前に厳密な復元計画を定めます。root qdiscを削除しても、任意の元の階層が再作成されるわけではありません。 新規に用意した使い捨て環境であれば、記録済みリソースIDだけを破棄することを復旧の境界にできます。 事前状態を再構成できない、または所有権が不明な場合、提案は設計のみのままにします。
完了と引き継ぎ
- [ ] Bootlinの公開資料とハードウェア環境の境界を説明し、資料/ツール/ヘルパーのバージョンを記録する。
- [ ] 実験カード、生データ、失敗/終了ステータス、観測範囲、前後のカウンターを保存する。
- [ ] 入力した休止時間と測定時間、キュー内のbyte数とメモリ、BDPと設定済みバッファーを区別する。
- [ ] 結果が遅い場合の妥当な説明を少なくとも2つ挙げ、それぞれを棄却する証拠を示す。
- [ ] 観測できなかったNIC/BPF/パケットの内容を明記し、測定していないスループット向上を主張しない。
- [ ] サーバー停止と、永続的な設定変更がないことを確認する。
- [ ] 説明を添えてクイズを完了する。
成果物を自動化の総合演習に提出します。 オーバーレイ/MTUについてはデータセンターEVPN、追加の経路境界についてはクラウド/CNI設計を参照してください。 次の専門分野を選ぶには、エキスパート編のコース一覧に戻ります。