毎日数千のリクエストを処理しているのに、ユーザーからは読み込みが遅いと苦情が来る?物理回線の帯域は十分あり、CPUもRAMもボトルネックではない——問題はほとんど誰も気にしないところにある:カーネルのデフォルトTCP輻輳制御アルゴリズムだ。
なぜCUBICがパフォーマンスの障壁になるのか?
LinuxはデフォルトでCUBICを使用している——kernel 2.6.19(2006年)から存在する輻輳制御アルゴリズムだ。CUBICの動作:ウィンドウサイズを徐々に増加させ、パケットロスに遭遇すると50%削減し、cubic関数に従って再び増加させる。一見問題なさそうだが、2つの根本的な問題がある:
- CUBICはパケットロスを輻輳のサインと見なす——しかし実際のロスは他の多くの原因(不安定な回線、一時的なバッファオーバーフロー)によって発生することもある
- RTTの高い接続では——例えばサーバーが東京にあり、ユーザーがハノイにいる場合——CUBICは最大帯域幅に達するまでに多くのラウンドトリップを必要とする。ウィンドウを削減するたびに、回復プロセスが非常に遅い
会社の古いCentOS 7サーバーでは、望ましいパフォーマンスを達成するためにかなり多くの最適化を行った——その中で最も明確な効果があった変更の一つが、TCP BBRへの移行だった。違いは国際接続で即座に現れた。
TCP BBRは問題に別のアプローチで取り組む
Googleは2016年にBBR(Bottleneck Bandwidth and Round-trip propagation time)を開発し、Linux kernel 4.9に統合した。パケットロスに反応する代わりに、BBRは回線の2つの物理パラメータを直接モデル化する:
- BtlBw(Bottleneck Bandwidth)——ボトルネック地点での実際の帯域幅
- RTprop(Round-trip propagation time)——純粋な信号伝播時間
BBRはこれら2つのパラメータを継続的にプローブし、バッファをあふれさせずに最大スループットを達成するよう送信レートを調整する。結果として:使用可能な帯域幅が増加し、レイテンシが低下し、特にRTTの大きい接続やランダムなパケットロスがある環境で効果的だ。
CUBIC vs BBR——数値だけでなく、メカニズムが異なる
- CUBIC:ウィンドウ増加 → ロス発生 → 50%削減 → 再増加。リアクティブで、適応が遅い
- BBR:帯域幅を継続的にプローブし、数学的モデルに従って送信レートを自動調整。プロアクティブで、ネットワーク条件の変化に素早く適応
GoogleはBBRがYouTubeのスループットを世界平均で4%改善し、低帯域幅接続では最大14%改善すると発表した。Googleの数百万の同時接続というスケールでは、4%は小さな数字ではない。
BBRを有効化するための条件
始める前に、以下の要件を確認すること:
- Kernelは4.9以降(このバージョンからBBRが統合されている)
- rootまたはsudo権限
- Ubuntu 18.04+、Debian 10+、CentOS 8+、AlmaLinux、Rocky Linuxはいずれもデフォルトで条件を満たす
CentOS 7はデフォルトでkernel 3.10を使用しており、BBRは含まれていない。事前にELRepo経由でkernelをアップグレードする必要がある(elrepo-kernelリポジトリからyum install kernel-ml)。
TCP BBRをステップごとに有効化する
ステップ1:現在の状態を確認する
# kernelバージョンを確認
uname -r
# 利用可能な輻輳制御アルゴリズムを確認
sysctl net.ipv4.tcp_available_congestion_control
# 現在使用中のアルゴリズムを確認
sysctl net.ipv4.tcp_congestion_control
Ubuntu 22.04での典型的な出力(BBR有効化前):
$ uname -r
5.15.0-88-generic
$ sysctl net.ipv4.tcp_available_congestion_control
net.ipv4.tcp_available_congestion_control = reno cubic
$ sysctl net.ipv4.tcp_congestion_control
net.ipv4.tcp_congestion_control = cubic
ステップ2:BBRモジュールをロードしてsysctlを設定する
# TCP BBRモジュールを即座にkernelにロード
modprobe tcp_bbr
# モジュールがロードされたことを確認
lsmod | grep bbr
次に、永続的に適用するために設定を/etc/sysctl.confに書き込む:
cat >> /etc/sysctl.conf << 'EOF'
# TCP BBR輻輳制御
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF
再起動なしで即座に適用:
sysctl -p
なぜnet.core.default_qdisc = fqが必要なのか? BBRはfq(Fair Queue)パケットスケジューラと組み合わせることで最も効果を発揮する。FQはフローごとにパケットを分配し、1つの接続がキューを独占することを防ぎ、デフォルトのpfifo_fastと比べてジッターを大幅に削減する。
起動のたびにBBRモジュールが自動的にロードされるように:
echo "tcp_bbr" >> /etc/modules-load.d/modules.conf
ステップ3:BBRが動作していることを確認する
# 現在使用中の輻輳制御を確認
sysctl net.ipv4.tcp_congestion_control
# BBRがavailableリストに表示されているはず
sysctl net.ipv4.tcp_available_congestion_control
# qdiscを確認
sysctl net.core.default_qdisc
期待される出力:
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_available_congestion_control = reno cubic bbr
net.core.default_qdisc = fq
関連するTCPパラメータでさらに最適化する
BBR単体でも明らかな改善をもたらす。しかし、いくつかの関連するTCPパラメータを組み合わせることで、パフォーマンスをさらに一段階引き上げられる。/etc/sysctl.confに追加する:
cat >> /etc/sysctl.conf << 'EOF'
# 高スループット接続用にバッファサイズを拡大
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
# TCP Fast Open:SYNパケットでデータを即送信、1 RTT削減
net.ipv4.tcp_fastopen = 3
# 多数の同時接続を持つサーバー用にバックログを拡大
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# ECNはBBRが輻輳をより正確に検出するのを支援
net.ipv4.tcp_ecn = 1
EOF
sysctl -p
TCP Fast Open(tcp_fastopen = 3)はWebサーバーに特に有効だ:クライアントが最初のSYNパケットでデータを送信することで、新規接続ごとに丸1 RTTを節約できる。RTT 80msの接続では、Webページの読み込みが80ms速くなることを意味する。
設定後の効果を確認する
ssコマンドを使ってBBRで動作中のTCP接続を観察する:
# 各TCP接続の輻輳制御を確認
ss -tin | grep bbr
# BBR統計を含む接続の詳細を確認
ss -tipm | grep -A 3 "ESTAB"
前後を比較するベンチマークにはiperf3を使う:
# iperf3をインストール
apt install iperf3 # Ubuntu/Debian
yum install iperf3 # CentOS/RHEL
# VPS上でサーバーモードを起動
iperf3 -s
# 別の場所のクライアントマシンから実行
# -t 30:30秒テスト、-P 4:4並列ストリーム
iperf3 -c YOUR_SERVER_IP -t 30 -P 4
Vultr東京VPS → ハノイのクライアント(RTT約80ms)で実際に計測した結果:CUBICと比べてスループットが約25〜30%向上し、ジッターが明らかに減少した。ネットワーク条件によって結果は異なるが、BBRが結果を悪化させることはほぼない——ワーストケースでCUBICと同等だ。
実際の運用上の注意点
- 4.9より古いkernel:事前にkernelをアップグレードする必要がある。CentOS 7はELRepo、Ubuntuは
apt install linux-generic-hwe-*を使う - BBR v2/v3:Googleは改善バージョンの開発を続けているが、まだmainline kernelにマージされていない。cloud kernel(GKE、AWS)やディストリビューション独自パッチを使用している場合は、kernel更新後に
sysctl net.ipv4.tcp_available_congestion_controlを実行して利用可能かどうかを確認する - コンテナ環境:Dockerコンテナはホストのネットワークnamespaceを使用する。BBRはホストレベルで有効化する必要があり、コンテナ内から設定することはできない
- 再起動不要:すべてのsysctl変更は即座に適用される。
modules-load.d経由でtcp_bbrモジュールが自動ロードされるようにするためだけに再起動が必要
まとめ
BBRの有効化は大した作業ではない:数行のsysctlコマンド、再起動なしで即座に適用、ロールバックはtcp_congestion_control = cubicに戻すだけ。アプリケーションコードに触れる必要もなく、ハードウェアの交換も不要だ。
最も明確な効果はクロスリージョン接続で現れる——東京サーバーとハノイユーザー、あるいはRTTが50ms以上の任意の組み合わせで。kernel 4.9+を実行するすべてのproductionサーバーにとって、これは最初にやるべき最適化だ:ワーストケースで何も変わらず、ベストケースではスループットが数十パーセント向上する。

