QUICをゆっくり解説(8):フロー制御

2021年09月15日 水曜日


【この記事を書いた人】
山本 和彦

Haskellコミュニティでは、ネットワーク関連を担当。 4児の父であり、家庭では子供たちと、ジョギング、サッカー、スキー、釣り、クワガタ採集をして過ごす。

「QUICをゆっくり解説(8):フロー制御」のイメージ

前回、QUICのストリームについて説明しました。今回は、ストリームのフロー制御についてお話しします。フロー制御はそれほど難しい機能ではないので、今回はほとんど用語整理のような内容になっております。

フロー制御と輻輳制御

ネットワーク通信の勉強をしていると、フロー制御と輻輳制御という用語を目にすることがあるかと思います。この2つは同一視されがちです。かくゆう僕も、長い間両者は同じ機能だと間違って理解していました。フロー制御と輻輳制御は、以下のように異なる仕組みです。

  • フロー制御:受信者の受信バッファが溢れないようにするための仕組みです。受信者が送信者に何らかの指示をし、送信者はその指示にしたがって送信するデータ量を調整します。
  • 輻輳制御:途中のネットワークが溢れないようにするための仕組みです。送信者は、なんらかの方法でパケットの欠落を検知します。パケットの欠落の有無によって、送信するデータ量を調整します。

実際に実装してみると分かりますが、フロー制御の実装はそれほど難しくありません。相手が許容する範囲でデータを送ればよいだけです。一方、輻輳制御の実装は、たとえ擬似コードが示されていたとしても、とても難しいです。輻輳制御については別の回で説明します。

QUICのフロー制御

QUICには3つのフロー制御があります。これらは HTTP/2に由来しています。

  • ストリームのフロー制御:それぞれのストリームに対する個別のフロー制御です。受信者は、ストリームの受信可能累積バイト数をMAX_STREAM_DATAフレームに入れて送信者に伝えます。
  • コネクションのフロー制御:コネクション内にある全ストリームに対するフロー制御です。受信者は、コネクションの受信可能累積バイト数をMAX_DATAフレームに入れて送信者に伝えます。
  • ストリーム数の制御:受信者は、1つのコネクションに対して作成してよい累積ストリーム数をMAX_STREAMSフレームに入れて送信者に伝えます。作成してよいストリームIDの最大値は、「max_streams * 4 + ストリームの種類ごとの最初の値」という計算で算出します。

「相手から伝えられた受信可能累積バイト数」から「自分で管理している現時点での送信バイト数」を引けば、送信してよいバイト数が算出できます。この値が0になると、送信者は送信をやめなければなりません。いわゆるブロックされた状態になります。

送信者がフロー制御によってブロックされた場合は、上記3つのそれぞれの場合に対して以下のフレームを送り、ブロックされたことを受信者に通知できます(送るのは必須ではありません)。

  • STREAM_DATA_BLOCKED
  • DATA_BLOCKED
  • STREAMS_BLOCKED

これらを受け取った受信者は、送信者側に送られるべきデータが存在していることが分かります。上記すべてのフレームは、伝搬中に欠落する可能性があるので、複数回送信してもよいことになっています。

送信者が、ストリームあるいはコネクションのバイト数の制限を守らず、過剰にデータを送信した場合、受信者は FLOW_CONTROL_ERROR としてコネクションを切ります。また、ストリーム数の制限を守らなかった場合は、STREAM_LIMIT_ERROR としてコネクションを切ります。コネクションの終了方法は、次回解説する予定です。

ウインドウとクレジット

TCPのフロー制御はウインドウに基づくと言われます。また、RFC7540では、HTTP/2のフロー制御はクレジットに基づくと説明されます。ウインドウとクレジットは、違う概念なのでしょうか?

QUIC実装者のコミュニティで質問したところ、クレジットという用語は、“Data And Computer Communications”という書籍が広めたと考えられるとのことでした。この本では、フロー制御を3つに大別しています。

  • バイナリ方式:受信者は受信データが多過ぎることを1ビットで表現して送信者に伝え、送信者は送信量を少なくする
  • クレジット方式:受信者が実際に受け取れるバイト数やパケット数を送信者に伝え、送信者はその制限を守って送信する
  • レート方式:受信者が実際に受け取れるレートを送信者に伝え、送信者はその制限を守って送信する

HTTP/2とQUICのフロー制御と同様に、TCPのフロー制御であるウインドウもクレジット方式の一種です。以下の図を見てください。

  • TCPでは、現在の受信可能バイト数(ウインドウ)を伝える
  • HTTP/2では、受信可能バイト数の差分を伝える
  • QUICでは、受信可能累積バイト数を伝える

山本 和彦

2021年09月15日 水曜日

Haskellコミュニティでは、ネットワーク関連を担当。 4児の父であり、家庭では子供たちと、ジョギング、サッカー、スキー、釣り、クワガタ採集をして過ごす。

Related
関連記事