【実務・中級編】 TCP輻輳制御:スロースタート、輻輳回避、高速再送のアルゴリズム – ネットワーク基礎とWebセキュリティ実践ガイド

こんにちは。現場でパケットの叫びを聞き続けて20年、シニアネットワークエンジニアの筆者です。

モダンなWebアプリケーションを開発していると、どうしても「レイテンシ」や「スループット」という言葉に敏感になりますよね。クラウドネイティブな時代、我々は Fetch API や axios を叩き、バックエンドでは gRPC や WebSockets が飛び交っています。しかし、その足元を支える「TCP」というプロトコルが、どれほど泥臭く、そして健気に「渋滞」と戦っているか、意識したことはあるでしょうか?

「なぜか特定の環境でAPIのレスポンスがガクンと落ちる」「帯域は太いはずなのに速度が出ない」――こうした問題の裏側には、必ずと言っていいほど TCP輻輳制御(Congestion Control) の挙動が隠れています。

今日は、OSI参照モデルのトランスポート層(第4層)で繰り広げられる、パケットたちの知られざる生存戦略について、実務に即した視点で解説していきましょう。

—

1. なぜ「輻輳制御」が必要なのか?

ネットワークの世界は、常に「欲張りな送信者」と「限界のあるルーター」の戦いです。

もしTCPに制御がなければ、送信側はリンクの限界までパケットを叩き込みます。すると、途中のルーターのバッファが溢れ(バッファオーバーフロー)、パケットがドロップします。ドロップすれば再送が発生し、さらに帯域を圧迫する……。これが「輻輳崩壊」です。

これを防ぐために、TCPは 「ネットワークがどれくらい混んでいるか」を、パケットの届き具合(ACKの返り方)から推測 します。

重要な2つのウィンドウ

  • rwnd (Receiver Window): 受信側が「今はこれだけしか受け取れないよ」と申告するサイズ。
  • cwnd (Congestion Window): 送信側が「ネットワークの混み具合から判断して、これくらいなら送っても大丈夫だろう」と自制するサイズ。

実際の送信データ量は、min(cwnd, rwnd) で決まります。輻輳制御アルゴリズムの真髄は、この cwnd をいかにダイナミックに、かつ賢く増減させるかにあります。

—

2. 伝統的なアルゴリズムの3つのフェーズ

TCPの輻輳制御は、主に「スロースタート」「輻輳回避」「高速再送・高速回復」というステップを踏みます。

① スロースタート (Slow Start)

「スロー」という名前ですが、実は指数関数的に加速する最もアグレッシブな段階です。
1つのパケット(セグメント)を送ってACKが返ってきたら、次は2個、その次は4個……と、cwnd を倍々に増やしていきます。

  • 実務上のポイント: 初期の cwnd(initcwnd)は、かつては1〜3でしたが、現在のLinuxカーネルではデフォルトで 10 に設定されています(RFC 6928)。これは、一般的なWebページの初期表示データを1ラウンドトリップ(RTT)で送り切るための最適解です。

② 輻輳回避 (Congestion Avoidance)

cwnd が一定のしきい値(ssthresh)に達すると、慎重なモードに切り替わります。
倍々ゲームをやめ、1往復ごとに cwnd を 1 つずつ増やす「線形増加」に入ります。

③ 高速再送 (Fast Retransmit) と高速回復 (Fast Recovery)

パケットが1つだけ落ちた場合、受信側は「抜けているパケット」を催促するために、同じACK番号を何度も返します。
「3回の重複ACK(Duplicate ACKs)」 を受け取った瞬間、送信側はタイマーを待たずに即座に再送を行います。これが「高速再送」です。

—

3. アルゴリズムの進化:Tahoe, Reno, そして Cubic

時代の変遷とともに、この cwnd の制御ロジックは進化してきました。

  • TCP Tahoe: パケットロスを検知したら、cwnd を 1 まで一気に落とす。まさに「石橋を叩き壊して渡る」古風な仕様。
  • TCP Reno: 現在の基礎。重複ACKによるロスなら、cwnd を半分にするだけで済ませる(高速回復)。
  • TCP Cubic: 現在のLinux(Ubuntu, CentOS等)のデフォルト。
  • 特徴:時間の3次関数を用いて cwnd を制御します。帯域が広い環境では一気に増やし、限界に近づくと緩やかに探りを入れる、非常に洗練されたアルゴリズムです。

—

4. インフラ・開発現場で使える実践テクニック

ここからは、シニアエンジニアが現場で使う「確認と設定」のTipsです。

Linuxサーバーの輻輳制御アルゴリズムを確認する

あなたのサーバーが今、どのアルゴリズムを使っているか知っていますか? 以下のコマンドで一発です。

# 現在利用可能なアルゴリズムを表示
sysctl net.ipv4.tcp_available_congestion_control

# 現在適用されているアルゴリズムを表示(多くの場合 'cubic' または 'bbr')
sysctl net.ipv4.tcp_congestion_control

もし、Googleが開発した最新の BBR(パケットロスではなく遅延をベースに制御するアルゴリズム)に変えたい場合は、以下のように設定します。

# BBRを有効化する設定(root権限が必要)
# /etc/sysctl.conf に追記することで恒久化可能
sudo sysctl -w net.core.default_qdisc=fq
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr

Pythonでソケットの状態を覗き見る

Web APIのパフォーマンスが出ないとき、アプリケーション層からTCPの状態をサンプリングすることがあります。Pythonの getsockopt を使うと、現在の cwnd などの生の情報が取得できます。

import socket
import struct

# ダミーの接続(例:自社のAPIサーバー)
target_host = "example.com"
target_port = 80

with socket.create_connection((target_host, target_port)) as sock:
    # HTTPリクエストを送信
    sock.sendall(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
    
    # TCP_INFO 構造体を取得(Linux固有)
    # 構造体のフォーマットはカーネルのバージョンにより異なります
    tcp_info_raw = sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_INFO, 1024)
    
    # 構造体をアンパック(抜粋:状態、オプション、cwndなど)
    # 以下のオフセットは一般的な環境の例です
    unpacked_info = struct.unpack("B" * (len(tcp_info_raw)), tcp_info_raw)
    
    # Linuxの tcp_info 構造体で cwnd は特定のインデックスにある
    # 実際には 'ss' コマンドで見るのが手っ取り早いが、コード内での監視に有効
    print(f"Current Congestion Window (cwnd): {unpacked_info[28]}")

デバッグの神ツール: ss コマンド

netstat はもう古い。現場では ss コマンドを使い倒しましょう。-i オプションをつけると、TCPの内部パラメータが丸見えになります。

# 特定のポートへの接続状況と、その内部パラメータ(cwnd, rtt等)を表示
ss -ti sport = :443

出力結果に含まれる cwnd:10 や ssthresh:7 という数字を追うことで、「あ、今スロースタートで詰まってるな」とか「頻繁に再送が発生して cwnd が絞られているな」といった、物理レイヤーに近い問題の切り分けが可能になります。

—

5. Web API設計者へのメッセージ

「APIのレスポンスが遅い」と感じたとき、コードを最適化する前に、「TCPコネクションの使い回し(Keep-Alive)」 ができているか確認してください。

新規にTCPコネクションを張るたびに、TCPは「スロースタート」からやり直しになります。つまり、せっかくの太い帯域も、接続直後は数パケットずつしか送れません。
特にデータ量の多いJSONを返すAPIや、高頻度な通信を行うマイクロサービス間では、initcwnd の壁を意識することが、パフォーマンス改善の大きな鍵となります。

まとめ

TCP輻輳制御は、インターネットという巨大な共有資源を、みんなで公平に、かつ効率的に使うための「知恵」の結晶です。

  • スロースタート: 最初は慎重に、でも急加速。
  • 輻輳回避: 限界が見えたら一歩ずつ。
  • Cubic/BBR: 現代の高速ネットワークに最適化された賢い制御。

パケットがネットワークを駆け抜けるその一瞬一瞬に、こうした緻密な計算が行われている。それを想像しながらコードを書くようになれば、あなたも立派な「ネットワークに強いエンジニア」です。

次は、Wiresharkを開いて、実際に cwnd が増減するグラフを眺めてみてください。きっと、昨日よりもパケットが愛おしく見えるはずです。

コメント

タイトルとURLをコピーしました