ボトルネックのジレンマ:物理リンク速度が実測値と一致しない理由
最新の10 Gbpsデータセンター間リンクをプロビジョニングしたとします。しかし、PostgreSQLのレプリカ同期やオフサイトバックアップを実行してみると、転送速度はわずか450 Mbps程度に低迷します。速度が低下すると、責任の擦り付け合いが始まります。クラウド事業者はアプリケーションを疑い、ストレージ担当はトップオブラック(ToR)スイッチを疑い、ネットワーク管理者はインターフェースカウンタのCRCエラーがゼロであることを主張します。
物理リンクの定格容量は、あくまで物理層におけるワイヤースピードを保証しているにすぎません。実際のスループットは、トランスポートプロトコル、レイテンシ、フレームロス、そしてカーネルのソケットバッファに大きく左右されます。基本的なpingコマンドは往復時間(RTT)を測定できますが、実際のトラフィックはほとんど流しません。また、rsyncやscpのようなユーティリティは、ディスクI/O、SSH暗号化のオーバーヘッド、シングルスレッドによるCPU制限の影響を受けるため、ネットワーク自体の真のボトルネックを見えにくくしてしまいます。
根本原因を突き止めるには、ストレージ層とアプリケーション層を完全に排除して計測する必要があります。そこで役立つのが、iPerf3による合成ベンチマークです。
基本概念:TCPウィンドウ、UDPプロファイリング、BDP計算式
やみくもにベンチマークを実行しても、得られる数値を見誤るだけです。結果を正しく解釈するためには、TCPとUDPが内部でパケット送信をどのように処理しているかを理解しておく必要があります。
1. 帯域遅延積(BDP)
TCPはスライディングウィンドウ方式を採用しています。送信側はデータを無制限に送り続けることはできず、受信側からの確認応答(ACK)を待つ必要があります。特定のマイクロ秒において、回線上に滞留(インフライト)可能な未確認データの最大容量を示すのが「帯域遅延積(Bandwidth-Delay Product: BDP)」です。
BDP = 帯域幅 (bits/sec) × 往復時間 (seconds)
例として、フランクフルト(eu-central-1)とバージニア(us-east-1)間のAWS Transit Gatewayリンクを考えてみましょう。帯域幅が1 Gbps、RTTが80 msの場合、計算は以下のようになります。
BDP = 1,000,000,000 bps × 0.080 s = 80,000,000 bits = 10 メガバイト
この回線をフルに使い切るには、送信側が常に10 MBのデータを回線上に滞留させておく必要があります。もしLinuxの受信・送信ウィンドウバッファ(tcp_rmemおよびtcp_wmem)の上限がデフォルトの2 MBのままであれば、ソケットから2 MBが送信された時点で単一TCPストリームはACK待ちのため停止します。その結果、シングルストリームのスループットは約200 Mbps(2 MB / 0.080 s)に制限され、1 Gbpsの回線容量の80%が完全に無駄になってしまいます。
2. TCP輻輳制御 vs UDPストレステスト
TCPはパケットロスが発生すると急激に速度を落とします。CUBICなどのパケットロスベースの輻輳制御アルゴリズムは、パケットドロップをルーターの過負荷と判断し、輻輳ウィンドウを一気に半減させるため、スループットが急落します。一方、UDPはACKを待つことも速度を絞ることもなく、パケットを回線へ送り続けます。一定のビットレートでUDPトラフィックを送信することで、iPerf3は以下の2つの重要なハードウェア指標を可視化できます。
- ジッター(Jitter):パケット到達時間のミリ秒単位のばらつき。高いジッターは、リアルタイム音声ストリーム、ビデオ配信、Raftコンセンサスのハートビートなどを大きく乱します。
- データグラムロス:特定レート(250 Mbps、500 Mbps、2 Gbpsなど)におけるパケットドロップ率。これにより、トランシーバーの光モジュール不良、光ファイバーの汚れ、スイッチバッファの枯渇などを特定できます。
実践演習:詳細ベンチマークとボトルネック診断
ステップ1:テスト用サーバーとクライアントの構築
テスト対象となる両方のホストにiPerf3をインストールします。
# Debian/Ubuntuの場合
sudo apt update && sudo apt install -y iperf3
# RHEL/AlmaLinux/Rockyの場合
sudo dnf install -y iperf3
受信側ノードでサーバーをデーモンとして起動します。トラフィックが誤ってパブリックゲートウェイを経由しないよう、内部インターフェースに直接バインドします。
# 対象の内部IPにバインド
iperf3 -s -B 10.10.20.15 -p 5201 -D
クライアントを実行する前に、ファイアウォール(nftables、iptables、またはセキュリティグループ)でポート5201のTCPおよびUDPの両方が開放されていることを確認してください。
ステップ2:シングルストリームTCP vs マルチストリーム飽和テスト
クライアントマシンから、レポート間隔1秒で20秒間のTCPテストを実行します。
iperf3 -c 10.10.20.15 -t 20 -i 1
特に注意して監視すべき列は、Retr(TCP再送回数)とCwnd(輻輳ウィンドウサイズ)の2点です。Retrの数値が増加し、同時にCwndが縮小している場合は、ネットワーク経路の途中でパケットロスが発生していることを示しています。
次に、-Pフラグを使用して並行ストリームをテストします。このシンプルなテストにより、速度低下の原因がレイテンシによるものか、物理リンクの飽和によるものかを判別できます。
iperf3 -c 10.10.20.15 -t 20 -P 4
1ストリームでは250 Mbpsで頭打ちになるものの、4ストリーム並行で1 Gbpsのインターフェースに対して980 Mbpsに達する場合、物理ケーブルやスイッチに問題はありません。ボトルネックとなっているのは、高遅延環境におけるTCPバッファの上限です。
ステップ3:UDPを用いたジッターとパケットロス閾値の診断
TCPは自動再送機能によって物理的なパケットドロップを隠蔽してしまいます。UDPモード(-u)に切り替えることで、中継機器のどこでフレームがドロップしているかを明らかにできます。想定されるリンク速度よりも十分に低い値から開始し、徐々に引き上げていきます。
# 500 Mbpsで回線の安定性をプローブ
iperf3 -c 10.10.20.15 -u -b 500M -t 15 -i 1
テスト終了時のサマリーテーブルを確認します。
[ ID] Interval Transfer Bitrate Jitter Lost/Total Datagrams
[ 5] 0.00-15.00 sec 894 MBytes 500 Mbits/sec 0.041 ms 0/647820 (0%)
レートを-b 800M、次に-b 950Mへと引き上げます。820 Mbpsまではロスが0.1%未満に抑えられていたにもかかわらず、それを超えると2.5%以上に急増する場合、そこが限界値です。このポイントでスイッチASICのバッファが枯渇していることが分かります。
ステップ4:非対称ルーティングと双方向通信の検証
ネットワーク経路は往路と復路で完全に対称であるとは限りません。非対称ルーティングポリシーやマルチプロバイダーのトランジットリンクでは、アップリンクとダウンリンクで挙動が異なるケースが多々あります。テスト環境を切り替えることなく、逆方向の経路を検証できます。
# リバースモード:サーバーが送信、クライアントが受信
iperf3 -c 10.10.20.15 -t 15 -R
# 同時双方向テスト
iperf3 -c 10.10.20.15 -t 15 --bidir
順方向のトラフィックが940 Mbpsに達する一方で、逆方向が120 Mbpsで頭打ちになる場合は、ルーティングテーブルを確認してください。MTUの不一致、非対称なルーティング経路、あるいは上流のエッジルーターによる過度な送信トラフィックシェーピングが原因と考えられます。
ステップ5:バッファ上限の制約を解消する
長距離を結ぶリンクでは、Linuxのデフォルトソケットバッファがスループットのボトルネックになります。システム設定ファイルを変更する前に、iPerf3の-wフラグを使って大きなバッファサイズを即座にテストできます。
# 8メガバイトのTCPウィンドウを強制
iperf3 -c 10.10.20.15 -t 20 -w 8M
転送速度が200 Mbpsから一気に920 Mbpsに跳ね上がった場合、カーネル設定が制限の原因です。双方のサーバーで/etc/sysctl.d/99-network-tuning.confを開き、バッファ上限を更新します。
# OSの最大受信・送信ソケットメモリを32MBに拡張
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
# TCP自動チューニングの設定:min default max(バイト単位)
net.ipv4.tcp_rmem = 4096 87380 33554432
net.ipv4.tcp_wmem = 4096 65536 33554432
# Fair QueuingとBBR輻輳制御を有効化
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
OSを再起動せずに、新しいパラメータを直ちに反映します。
sudo sysctl --system
このsysctl設定を適用することで、リージョン間を跨ぐRedisクラスタやMySQLリードレプリカの同期速度が倍増することが珍しくありません。高額な回線アップグレード費用をかけずに、遅延の課題を解消できます。
ステップ6:テスト中のライブソケット診断
一方のターミナルでiPerf3を実行したまま、もう一つのシェルを開いてssコマンドでカーネルソケットのリアルタイムカウンタを監視します。
ss -tin '( dport = :5201 or sport = :5201 )'
これにより、平滑化されたRTT(rtt)、最大セグメントサイズ(mss)、ペーシングレート、再送カウンタなどのライブメトリクスをカーネルから直接取得できます。インターフェースが標準の1500バイトMTUを使用しているにもかかわらず、mssが1460ではなく1360と表示される場合、経路上のIPSecトンネルやクラウドオーバーレイがパケットサイズを制限しています。Path MTU Discoveryを修正するか、TCP MSSクランピングを調整してパケットの断片化(フラグメンテーション)を防ぎましょう。
まとめ:診断手順のルーティン化
ネットワーク速度の低下を切り分けるには、体系的なアプローチが不可欠です。まずは単一のTCPストリームから開始し、並行ストリームで全体容量を把握します。次にレート制限付きのUDPを用いてパケットロスを分離し、最後に帯域遅延積(BDP)を算出してカーネルバッファを最適化します。
新たなデータセンター間回線を導入する際は、必ずベンチマークを実施してベースラインの数値を記録しておきましょう。半年後にアプリケーションのパフォーマンスが低下した際、問題が物理回線にあるのかアプリケーションコードにあるのかを、わずか数分で見極められるようになります。

