TCPの秘密兵器:ネットワークフロー制御とネットワーク輻輳制御

TCP信頼性トランスポート
TCPプロトコルは信頼性の高いトランスポートプロトコルとして広く知られていますが、どのようにしてトランスポートの信頼性を確保しているのでしょうか?

信頼性の高いデータ伝送を実現するには、データの破損、損失、重複、順序の乱れなど、多くの要因を考慮する必要があります。これらの問題が解決されない限り、信頼性の高いデータ伝送は実現できません。

そのため、TCPはシーケンス番号、確認応答、再送制御、接続管理、ウィンドウ制御などのメカニズムを用いて、信頼性の高い伝送を実現している。

本稿では、TCPのスライディングウィンドウ、フロー制御、輻輳制御に焦点を当てる。再送メカニズムについては、次節で別途解説する。

ネットワークフロー制御
ネットワークフロー制御、またはネットワークトラフィック制御として知られるものは、実際にはプロデューサーとコンシューマー間の微妙な関係の現れです。おそらく、仕事や面接でこのようなシナリオに何度も遭遇したことがあるでしょう。プロデューサーの生成能力がコンシューマーの消費能力を大幅に上回ると、キューが際限なく増大します。より深刻なケースでは、RabbitMQメッセージが過剰に蓄積されると、MQサーバー全体のパフォーマンスが低下する可能性があることをご存知かもしれません。TCPについても同様です。制御されないまま放置すると、ネットワークにメッセージが過剰に送り込まれ、コンシューマーは処理能力を超え、プロデューサーは重複したメッセージを送信し続けるため、ネットワークのパフォーマンスに大きな影響を与えます。

この現象に対処するため、TCPは送信側が受信側の実際の受信容量に基づいて送信データ量を制御するメカニズム(フロー制御)を提供します。受信側は受信ウィンドウを、送信側は送信ウィンドウを保持します。これらのウィンドウは単一のTCP接続専用であり、すべての接続がウィンドウを共有するわけではないことに注意してください。

TCPは、受信ウィンドウを表す変数を用いることでフロー制御を実現します。受信ウィンドウは、送信側がキャッシュの空き容量を把握するための指標となります。送信側は、受信側の実際のデータ受信容量に応じて送信するデータ量を制御します。

受信ホストは、受信可能なデータのサイズを送信者に通知し、送信者はその制限までデータを送信します。この制限はウィンドウサイズと呼ばれ、TCPヘッダーに記載されています。受信ウィンドウフィールドは、受信側が受信可能な、または受信しようとするバイト数を示すために使用されます。

送信側ホストは、受信側ホストがデータを受け入れることができるかどうかを検出するために、定期的にウィンドウプローブパケットを送信します。受信側バッファがオーバーフローする恐れがある場合、送信側に送信するデータ量を制御するように指示するために、ウィンドウサイズが小さい値に設定されます。

ネットワークフロー制御の図を以下に示します。

交通規制

ネットワーク輻輳制御
輻輳制御を導入する前に、受信ウィンドウと送信ウィンドウに加えて、輻輳ウィンドウも存在することを理解する必要があります。輻輳ウィンドウは主に、送信側が受信ウィンドウにデータを送信する速度を決定するために使用されます。したがって、輻輳ウィンドウもTCP送信側によって管理されます。送信するデータが少なすぎても多すぎても理想的ではないため、送信するデータの量を決定するアルゴリズムが必要です。これが輻輳ウィンドウの概念の由来です。

従来のネットワークフロー制御では、送信側が受信側のキャッシュをデータで埋め尽くすことを回避していましたが、ネットワーク内で何が起こっているかは把握できていませんでした。一般的に、コンピュータネットワークは共有環境にあります。そのため、他のホスト間の通信によってネットワークの輻輳が発生する可能性があります。

ネットワークが混雑している状態で大量のパケットが送信され続けると、遅延やパケット損失などの問題が発生する可能性があります。この場合、TCPはデータを再送信しますが、再送信によってネットワークへの負荷が増大し、結果として遅延やパケット損失がさらに悪化します。これは悪循環に陥り、ますます深刻化する可能性があります。

したがって、TCPはネットワーク上で何が起こっているかを無視することはできません。ネットワークが混雑している場合、TCPは送信するデータ量を減らすことで自らを犠牲にします。

そこで、送信側からのデータでネットワーク全体が満杯になるのを防ぐことを目的とした輻輳制御が提案されている。送信側が送信すべきデータ量を調整するために、TCPは輻輳ウィンドウと呼ばれる概念を定義している。輻輳制御アルゴリズムは、ネットワークの輻輳度に応じて輻輳ウィンドウのサイズを調整し、送信側が送信するデータ量を制御する。

輻輳ウィンドウとは何ですか?これは送信ウィンドウとどのような関係がありますか?

輻輳ウィンドウは、送信側が管理する状態変数であり、送信側が送信できるデータ量を決定します。輻輳ウィンドウは、ネットワークの輻輳レベルに応じて動的に変化します。

送信ウィンドウとは、送信者と受信者の間で合意されたウィンドウサイズであり、受信者が受信できるデータ量を示します。輻輳ウィンドウと送信ウィンドウは関連しており、送信ウィンドウは通常、輻輳ウィンドウと受信ウィンドウの最小値、つまり swnd = min(cwnd, rwnd) となります。

輻輳ウィンドウcwndは以下のように変更されます。

ネットワークに輻輳が発生していない場合、つまり再送信タイムアウトが発生しない場合、輻輳ウィンドウは拡大します。

ネットワークに混雑が発生すると、混雑ウィンドウが縮小します。

送信側は、指定された時間内にACK確認応答パケットが受信されるかどうかを監視することで、ネットワークが混雑しているかどうかを判断します。送信側が指定された時間内にACK確認応答パケットを受信しない場合、ネットワークは混雑しているとみなされます。

輻輳ウィンドウに加えて、TCP輻輳制御アルゴリズムについても説明しましょう。TCP輻輳制御アルゴリズムは、主に次の3つの部分から構成されています。

出だしが遅い:初期状態では、cwnd輻輳ウィンドウは比較的小さく、送信側はネットワークの容量に迅速に対応するために、輻輳ウィンドウを指数関数的に増加させます。
渋滞回避:輻輳ウィンドウが一定のしきい値を超えると、送信側は輻輳ウィンドウの増加率を緩やかにし、ネットワークの過負荷を回避するために、輻輳ウィンドウを線形的に増加させる。
迅速な復旧:輻輳が発生した場合、送信側は輻輳ウィンドウを半分に縮小し、高速回復状態に移行して、受信した重複ACKを通じてネットワーク回復の場所を特定し、その後、輻輳ウィンドウを再び拡大します。

出だしが遅い
TCP接続が確立されると、輻輳ウィンドウcwndは初期値として最小MSS(最大セグメントサイズ)に設定されます。これにより、初期送信レートは約MSS/RTTバイト/秒となります。実際の利用可能な帯域幅は通常MSS/RTTよりもはるかに大きいため、TCPは最適な送信レートを見つけようとします。これはスロースタートによって実現できます。

スロースタート処理では、輻輳ウィンドウcwndの値は1 MSSに初期化され、送信されたパケットセグメントが確認応答されるたびにcwndの値は1 MSSずつ増加し、2 MSSになります。その後、パケットセグメントの送信が成功するたびにcwndの値は倍になり、これを繰り返します。具体的な増加プロセスは、次の図に示されています。

 ネットワーク輻輳制御

しかし、送信レートは常に増加するわけではなく、いつかは増加が止まる必要があります。では、送信レートの増加はいつ終わるのでしょうか?スロースタートの場合、送信レートの増加は通常、以下のいずれかの方法で終了します。

最初の方法は、スロースタートの送信プロセス中にパケット損失が発生した場合です。パケット損失が発生すると、TCPは送信側の輻輳ウィンドウcwndを1に設定し、スロースタートプロセスを再開します。ここで、スロースタートしきい値ssthreshという概念が導入されます。その初期値は、パケット損失が発生したcwndの値の半分です。つまり、輻輳が検出されたとき、ssthreshの値はウィンドウ値の半分になります。

2つ目の方法は、スロースタートしきい値ssthreshの値と直接相関させることです。輻輳が検出されたとき、ssthreshの値はウィンドウ値の半分になるため、cwndがssthreshより大きい場合、倍増するたびにパケット損失が発生する可能性があります。したがって、cwndをssthreshに設定するのが最善です。これにより、TCPは輻輳制御モードに切り替わり、スロースタートが終了します。

スロースタートが終了する最後の方法は、冗長なACKパケットが3つ検出された場合です。この場合、TCPは高速再送信を実行し、回復状態に入ります。(ACKパケットが3つある理由が不明な場合は、再送信メカニズムの項で別途説明します。)

渋滞回避
TCPが輻輳制御状態に入ると、cwndは輻輳閾値ssthreshの半分に設定されます。これは、パケットセグメントを受信するたびにcwndの値が2倍になることはないことを意味します。代わりに、比較的保守的なアプローチが採用され、送信が完了するたびにcwndの値は1 MSS(最大パケットセグメント長)だけ増加します。たとえば、10個のパケットセグメントが確認応答された場合でも、cwndの値は1 MSSだけ増加します。これは線形成長モデルであり、成長の上限もあります。パケット損失が発生すると、cwndの値はMSSに変更され、ssthreshの値はcwndの半分に設定されます。または、3つの冗長ACK応答を受信すると、MSSの増加も停止します。cwndの値を半分にした後も3つの冗長ACKが受信された場合、ssthreshの値はcwndの半分として記録され、高速回復状態に入ります。

高速回復
高速回復状態では、受信した冗長ACK(つまり、順序通りに届かないACK)ごとに、輻輳ウィンドウcwndの値が1MSSずつ増加します。これは、ネットワーク内で正常に送信されたパケットセグメントを有効活用し、伝送効率を最大限に向上させるためです。

パケット損失セグメントのACKが到着すると、TCPはcwndの値を減少させ、輻輳回避状態に入ります。これは、輻輳ウィンドウのサイズを制御し、ネットワークの輻輳がさらに増大するのを防ぐためです。

輻輳制御状態の後にタイムアウトが発生した場合、ネットワークの状態はより深刻になり、TCPは輻輳回避状態からスロースタート状態に移行します。この場合、輻輳ウィンドウcwndの値は最大パケットセグメント長である1 MSSに設定され、スロースタートしきい値ssthreshの値はcwndの半分に設定されます。これは、ネットワークが回復した後に輻輳ウィンドウのサイズを徐々に増やし、伝送速度とネットワークの輻輳度のバランスを取ることを目的としています。

まとめ
信頼性の高いトランスポートプロトコルであるTCPは、シーケンス番号、確認応答、再送制御、接続管理、ウィンドウ制御によって信頼性の高いトランスポートを実現します。中でも、フロー制御メカニズムは、受信側の実際の受信容量に応じて送信側が送信するデータ量を制御し、ネットワークの輻輳やパフォーマンスの低下といった問題を回避します。輻輳制御メカニズムは、送信側が送信するデータ量を調整することで、ネットワークの輻輳の発生を回避します。輻輳ウィンドウと送信ウィンドウの概念は相互に関連しており、送信側のデータ量は輻輳ウィンドウのサイズを動的に調整することで制御されます。スロースタート、輻輳回避、高速回復は、TCP輻輳制御アルゴリズムの3つの主要部分であり、ネットワークの容量や輻輳度に応じて、さまざまな戦略を用いて輻輳ウィンドウのサイズを調整します。

次のセクションでは、TCPの再送メカニズムについて詳しく見ていきます。再送メカニズムは、TCPが信頼性の高い伝送を実現するための重要な要素です。失われたデータ、破損したデータ、または遅延したデータを再送することで、データの信頼性の高い伝送を保証します。次のセクションでは、再送メカニズムの実装原理と戦略について詳しく解説します。お楽しみに!


投稿日時:2025年2月24日