TCP のフロー制御の実装
TCP ではデータ (セグメント) を受信したことを ACK で相手に知らせますが、TCP セグメントを受信するたびに ACK を返していては効率が悪いので、TCP では、規定の量の TCP セグメントを受信するまで ACK を返さなくてよい、ということになっています。その仕組みを Windowと呼びます。
「規定の量」とは、自身が受信できる量をリアルタイムで相手に通知します。具体的には「Window」フィールドとオプションの「Window Scale」で決定されます。
例えば「Window : Ox2000 = 8192 Bytes = 8 KB」、「Window Scale : Ox08 = 2^8 = 256 倍」だった場合、8 KB * 256 = 2 MB となります。
この場合、2 MB のデータを受け取るまで、ACK を返さなくてもよいのです。なお、これらの数値は自身の「受信バッファ」の懐具合で自ら決定します。
まずはこの初期値でデータ送受信を開始しますが、データ受信をするたびに、受信処理できるバッファが減っていきます。その状況をリアルタイムで伝えるのがスライディング Windowです。
スライディング Window
スライディング Window は、自身のバッファの懐具合をリアルタイムで相手に伝える仕組みで、フロー制御の実装になります。最初に決定した Window の規定量から、TCP セグメントを受信して処理中のために使用中のバッファを差し引いた値を、同じく「Window」フィールドを使って相手に伝えます。
その Window フィールドを受信した相手はまたそれに応じたデータ分を、ACK 無しに送ることができます。つまり、メモリバッファに余裕があるときは窓を開け、余裕が無くなってきたら窓を閉める動きをするのです。この仕組みにより通信を効率化します。
ただし、これはあくまで、ホストの受信バッファがこれだけある、という、ホストだけの都合であることに注意して下さい。
TCP の輻輳制御の実装
スロースタートアルゴリズム
前回の例で、いきなり 2 MB 分送ると (ホストではなく) ネットワークのキャパシティオーバーになってしまう可能性があります。そうなるとまた効率が悪いので、ネットワークの都合も考える必要があります。スロースタートはネットワークの都合を考慮した輻輳制御の実装です。RFC5681 で定義されています。
このアルゴリズムを管理するパラメータとして以下 2 つがあります。共に単位は Byte です。
- Congestion Window (CW)
- Slow Start Threshold (SST)
CW は基本的に MSS の整数倍です。初期値 / MSS の数だけパケットを送信し、送信データが SST の値に達するまで倍に増やしていきます。
閾値を超えたら輻輳を検知するまで、数パケットずつ増やしていき、輻輳を検知した場合は CW は初期値に戻り、SST は RTO 発生直前の CW の半分にセットされます。
このように『増やすときは数パケットずつ足し算、減らすときは掛け算』という方式を "Additive-Increase, Multiplicative-Decrease (AIMD)" と呼び、RFC2861 に記述されています。
なお、輻輳の検知方法としては 2 つあり、1 つはRTO の時間が経っても ACK が返されない場合、もう 1 つは RTO 内だが Dup ACK によりパケットロスが検知された場合です。
なお、Windows10 では、CW の初期値は 10*MSS になったようです。(Windows8.1 までは 4 * MSS)
nesukeの推薦図書
以下に該当する人なら熟読することを強く推奨します。
- 周りのネットワークエンジニアよりも一歩抜き出た存在となり、価値を高めたい!
- サーバエンジニアだけどネットワークも含めた総合的なセキュリティへの理解も深めていきたい!
コメント