スライディングウィンドウ、スロースタート、AIMD(加算増加・乗算減少)によるTCPの流量制御メカニズム
TCPフロー制御は、送信側がネットワークと受信側の状況に応じて送信量を動的に調整する仕組みです。「ウィンドウ」と呼ばれるパラメータを使い、スロースタート・輻輳回避・パケットロス検出を組み合わせて、効率的かつ安全にデータを転送します。水道管を想像してください。蛇口を全開にすると大量の水が流れますが、受け手のバケツが小さければ溢れてしまいます。これがTCPにおける「フロー制御」の問題です。送信側はデータを高速に送れますが、受信側の処理が追いつかないとバッファがあふれ、データが失われます。TCPはこの問題を「受信ウィンドウ(rwnd)」で解決します。受信側が「今、私のバッファにはこれだけの空きがあります」と送信側に伝え、送信側はその量を超えないようにデータを送ります。もう一つの問題は道路の渋滞と同じです。あなた一人だけが車で走るなら道は空いていますが、みんなが一斉に道路に出ると大渋滞になります。ネットワークでも、多くのコンピュータが同時に大量のデータを送ると、ルーターやスイッチの処理能力を超えてパケットが廃棄されます。これが「輻輳(ネットワークの混雑)」です。TCPは「輻輳ウィンドウ(cwnd)」でこの問題に対処します。ネットワークの混雑度を推測しながら、送信量を動的に調整します。TCPが実際に送信できるデータ量は min(cwnd, rwnd) で決まります。つまり、受信側のバッファの空き(フロー制御)とネットワークの混雑度(輻輳制御)のうち、より厳しい制約が適用されます。Netflixの動画ストリーミングでも、Zoomのビデオ会議でも、裏側ではこのウィンドウ制御が1秒間に何十回も実行されており、ネットワーク環境に応じて自動的に送信速度を調整しています。上のツールで「スロースタート」シナリオを再生すると、ウィンドウサイズ(cwnd)がRTTごとにどう変化するかが確認できます。上段のグラフでcwndの増加パターンに注目してください。
ss -i コマンドで現在のcwnd値を確認できます。図の中の各正方形は1つのTCPセグメント(パケット)を表しています。緑色のセグメントはACKを受信済み(送信が完了した)データ、青色のセグメントは現在のウィンドウ内で送信可能なデータ、灰色のセグメントはウィンドウ外の未送信データです。紫色の破線枠がcwndの範囲を示しています。
ACKを受信すると、ウィンドウの左端が右に移動(スライド)します。例えば、セグメント1のACKが届くと、セグメント1が「ACK済み」(緑)になり、ウィンドウが右にスライドして新しいセグメント(灰色→青)が送信可能になります。これにより、ACKを待っている間も新しいデータの送信が可能で、ネットワーク帯域を無駄なく活用できます。
もしスライディングウィンドウがなければ、1パケット送信→ACK待ち→次のパケット送信...というストップ&ウェイト方式になります。RTTが100msの場合、1秒間にたった10パケット(約15KB)しか送れません。cwnd=100なら、1 RTTで100パケット(約150KB)を送信でき、スループットが100倍になります。