4. フロー制御
4. フロー制御
受信者は、高速な送信者に圧倒されたり、悪意のある送信者が大量のメモリを消費したりするのを防ぐために、バッファリングが必要なデータ量を制限する必要があります。受信者が接続のメモリコミットメントを制限できるようにするために、ストリームは個別に、および接続全体で、フロー制御されます。QUICレシーバーは、セクション 4.1 および 4.2 で説明されているように、送信者がストリーム上およびすべてのストリーム全体でいつでも送信できるデータの最大量を制御します。
同様に、接続内の並行性を制限するために、QUICエンドポイントは、セクション 4.6 で説明されているように、ピアが開始できるストリームの最大累積数を制御します。
CRYPTOフレームで送信されるデータは、ストリームデータと同じ方法ではフロー制御されません。QUICは、データの過度なバッファリングを避けるために暗号化プロトコル実装に依存します; [QUIC-TLS] を参照してください。複数のレイヤーでの過度なバッファリングを避けるために、QUIC実装は、暗号化プロトコル実装がそのバッファリング制限を通信するためのインターフェースを提供すべきです (SHOULD)。
4.1 データフロー制御
QUICは、受信者が特定のストリームまたは接続全体で受信する準備ができている合計バイト数の制限をアドバタイズする、制限ベースのフロー制御スキームを採用しています。これにより、QUICには2つのレベルのデータフロー制御があります:
-
ストリームフロー制御: 各ストリームで送信できるデータ量を制限することで、単一のストリームが接続の受信バッファ全体を消費することを防ぎます。
-
接続フロー制御: すべてのストリームのSTREAMフレームで送信されるストリームデータの合計バイト数を制限することで、送信者が受信者の接続バッファ容量を超えることを防ぎます。
送信者は、いずれかの制限を超えるデータを送信してはなりません (MUST NOT)。
受信者は、ハンドシェイク中にトランスポートパラメータを通じてすべてのストリームの初期制限を設定します (セクション 7.4)。その後、受信者はMAX_STREAM_DATAフレーム (セクション 19.10) またはMAX_DATAフレーム (セクション 19.9) を送信者に送信して、より大きな制限をアドバタイズします。
受信者は、対応するストリームIDでMAX_STREAM_DATAフレームを送信することで、ストリームのより大きな制限をアドバタイズできます。MAX_STREAM_DATAフレームは、ストリームの最大絶対バイトオフセットを示します。受信者は、そのストリームで消費されたデータの現在のオフセットに基づいて、アドバタイズするフロー制御オフセットを決定できます。
受信者は、MAX_DATAフレームを送信することで、接続のより大きな制限をアドバタイズできます。これは、すべてのストリームの絶対バイトオフセットの合計の最大値を示します。受信者は、すべてのストリームで受信したバイトの累積合計を維持し、これを使用してアドバタイズされた接続またはストリームデータ制限の違反をチェックします。受信者は、すべてのストリームで消費されたバイトの合計に基づいて、アドバタイズする最大データ制限を決定できます。
受信者が接続またはストリームの制限をアドバタイズすると、より小さい制限をアドバタイズすることはエラーではありませんが、より小さい制限は効果がありません。
送信者がアドバタイズされた接続またはストリームデータ制限に違反した場合、受信者はFLOW_CONTROL_ERRORタイプのエラーで接続をクローズしなければなりません (MUST); エラー処理の詳細についてはセクション 11 を参照してください。
送信者は、フロー制御制限を増加させないMAX_STREAM_DATAまたはMAX_DATAフレームを無視しなければなりません (MUST)。
送信者が制限までデータを送信した場合、新しいデータを送信できなくなり、ブロックされたと見なされます。送信者は、書き込むデータがあるがフロー制御制限によってブロックされていることを受信者に示すために、STREAM_DATA_BLOCKEDまたはDATA_BLOCKEDフレームを送信すべきです (SHOULD)。送信者がアイドルタイムアウト (セクション 10.1) より長い期間ブロックされている場合、送信可能なデータがある場合でも、受信者は接続をクローズする可能性があります。接続がクローズされないようにするために、フロー制御によって制限されている送信者は、フライト中にACKを誘発するパケットがない場合、定期的にSTREAM_DATA_BLOCKEDまたはDATA_BLOCKEDフレームを送信すべきです (SHOULD)。
4.2 フロー制御制限の増加
実装は、MAX_STREAM_DATAおよびMAX_DATAフレームでいつどのくらいのクレジットをアドバタイズするかを決定しますが、このセクションではいくつかの考慮事項を提供します。
送信者のブロックを避けるために、受信者はMAX_STREAM_DATAまたはMAX_DATAフレームをラウンドトリップ内で複数回送信するか、フレームの損失とその後の回復のための時間を確保できるように十分早く送信することができます (MAY)。
制御フレームは接続オーバーヘッドに寄与します。したがって、小さな変更でMAX_STREAM_DATAおよびMAX_DATAフレームを頻繁に送信することは望ましくありません。一方、更新の頻度が低い場合、送信者のブロックを避けるために制限のより大きな増分が必要になり、受信者でのより大きなリソースコミットメントが必要になります。アドバタイズされる制限の大きさを決定する際には、リソースコミットメントとオーバーヘッドの間にトレードオフがあります。
受信者は、ラウンドトリップ時間の推定値と受信アプリケーションがデータを消費する速度に基づいて、アドバタイズされる追加クレジットの頻度と量を調整するために、自動チューニングメカニズムを使用できます。これは、一般的なTCP実装と同様です。最適化として、エンドポイントは、送信する他のフレームがある場合にのみフロー制御に関連するフレームを送信することで、フロー制御が余分なパケットを送信する原因にならないようにすることができます。
ブロックされた送信者は、STREAM_DATA_BLOCKEDまたはDATA_BLOCKEDフレームを送信する必要はありません。したがって、受信者は、MAX_STREAM_DATAまたはMAX_DATAフレームを送信する前に、STREAM_DATA_BLOCKEDまたはDATA_BLOCKEDフレームを待ってはなりません (MUST NOT); そうすると、送信者が接続の残りの期間ブロックされる可能性があります。送信者がこれらのフレームを送信したとしても、それらを待つと、送信者が少なくとも完全なラウンドトリップの間ブロックされることになります。
送信者がブロックされた後にクレジットを受信すると、応答として大量のデータを送信できる可能性があり、短期的な輻輳が発生します; 送信者がこの輻輳を回避する方法についての議論は、[QUIC-RECOVERY] のセクション 7.7 を参照してください。
4.3 フロー制御のパフォーマンス
エンドポイントが、ピアがこの接続上で常にピアの帯域幅遅延積よりも大きい利用可能なフロー制御クレジットを持っていることを保証できない場合、その受信スループットはフロー制御によって制限されます。
パケット損失は、受信バッファにギャップを引き起こし、アプリケーションがデータを消費して受信バッファスペースを解放することを妨げる可能性があります。
タイムリーなフロー制御制限の更新を送信することで、パフォーマンスが向上します。フロー制御更新のみを提供するためにパケットを送信すると、ネットワーク負荷が増加し、パフォーマンスに悪影響を与える可能性があります。ACKフレームなどの他のフレームと一緒にフロー制御更新を送信すると、これらの更新のコストが削減されます。
4.4 ストリームキャンセルの処理
エンドポイントは、接続レベルのフロー制御のためにすべてのバイトを説明できるように、各ストリームで消費されたフロー制御クレジットの量について最終的に合意する必要があります。
RESET_STREAMフレームを受信すると、エンドポイントは一致するストリームの状態を破棄し、そのストリームに到着するさらなるデータを無視します。
RESET_STREAMは、ストリームの1つの方向を突然終了します。双方向ストリームの場合、RESET_STREAMは反対方向のデータフローに影響を与えません。両方のエンドポイントは、その方向が終端状態に入るまで、終了していない方向のストリームのフロー制御状態を維持しなければなりません (MUST)。
4.5 ストリームの最終サイズ
最終サイズは、ストリームによって消費されるフロー制御クレジットの量です。ストリーム上のすべての連続バイトが一度送信されたと仮定すると、最終サイズは送信されたバイト数です。より一般的には、これはストリーム上で送信された最大オフセットを持つバイトのオフセットよりも1大きい値、またはバイトが送信されていない場合はゼロです。
送信者は、ストリームがどのように終了されるかに関係なく、ストリームの最終サイズを常に確実に受信者に伝えます。最終サイズは、FINフラグを持つSTREAMフレームのOffsetフィールドとLengthフィールドの合計であり、これらのフィールドが暗黙的である可能性があることに注意してください。あるいは、RESET_STREAMフレームのFinal Sizeフィールドがこの値を運びます。これにより、両方のエンドポイントが、そのストリームで送信者によって消費されたフロー制御クレジットの量について合意することが保証されます。
エンドポイントは、ストリームの受信部分が「Size Known」または「Reset Recvd」状態に入ると、ストリームの最終サイズを知ります (セクション 3)。受信者は、接続レベルのフローコントローラーでストリーム上で送信されたすべてのバイトを説明するために、ストリームの最終サイズを使用しなければなりません (MUST)。
エンドポイントは、最終サイズに達したかそれを超えるストリーム上でデータを送信してはなりません (MUST NOT)。
ストリームの最終サイズが判明すると、それは変更できません。ストリームの最終サイズの変更を示すRESET_STREAMまたはSTREAMフレームが受信された場合、エンドポイントはFINAL_SIZE_ERRORタイプのエラーで応答すべきです (SHOULD); エラー処理の詳細についてはセクション 11 を参照してください。受信者は、ストリームがクローズされた後でも、最終サイズに達したかそれを超えるデータの受信をFINAL_SIZE_ERRORタイプのエラーとして扱うべきです (SHOULD)。これらのエラーを生成することは必須ではありません。なぜなら、エンドポイントにこれらのエラーを生成することを要求することは、エンドポイントがクローズされたストリームの最終サイズ状態を維持する必要があることも意味し、これは重大な状態コミットメントを意味する可能性があるためです。
4.6 並行性の制御
エンドポイントは、ピアが開くことができる着信ストリームの累積数を制限します。(max_streams * 4 + first_stream_id_of_type) 未満のストリームIDを持つストリームのみを開くことができます; 表 1 を参照してください。初期制限はトランスポートパラメータで設定されます; セクション 18.2 を参照してください。後続の制限は、MAX_STREAMSフレームを使用してアドバタイズされます; セクション 19.11 を参照してください。単方向ストリームと双方向ストリームには別々の制限が適用されます。
max_streamsトランスポートパラメータまたはMAX_STREAMSフレームが2^60より大きい値で受信された場合、これは可変長整数として表現できない最大ストリームIDを許可します; セクション 16 を参照してください。いずれかが受信された場合、違反する値がトランスポートパラメータで受信された場合はTRANSPORT_PARAMETER_ERRORタイプの接続エラーで、フレームで受信された場合はFRAME_ENCODING_ERRORタイプで、接続を直ちにクローズしなければなりません (MUST); セクション 10.2 を参照してください。
エンドポイントは、ピアによって設定された制限を超えてはなりません (MUST NOT)。送信した制限を超えるストリームIDを持つフレームを受信したエンドポイントは、これをSTREAM_LIMIT_ERRORタイプの接続エラーとして扱わなければなりません (MUST); エラー処理の詳細についてはセクション 11 を参照してください。
受信者がMAX_STREAMSフレームを使用してストリーム制限をアドバタイズすると、より小さい制限をアドバタイズしても効果はありません。ストリーム制限を増加させないMAX_STREAMSフレームは無視されなければなりません (MUST)。
ストリームおよび接続フロー制御と同様に、このドキュメントは、MAX_STREAMSを介してピアにいつどのくらいのストリームをアドバタイズするかを決定することを実装に任せています。実装は、ストリームがクローズされたときに制限を増やすことを選択して、ピアが利用できるストリームの数をほぼ一定に保つことができます。
ピアの制限により新しいストリームを開くことができないエンドポイントは、STREAMS_BLOCKEDフレームを送信すべきです (SHOULD) (セクション 19.14)。この信号はデバッグに役立つと見なされます。エンドポイントは、追加のクレジットをアドバタイズする前にこの信号の受信を待ってはなりません (MUST NOT)。そうすると、ピアが少なくとも完全なラウンドトリップの間ブロックされ、ピアがSTREAMS_BLOCKEDフレームを送信しないことを選択した場合は潜在的に無期限にブロックされることになります。