QUICはUDPなのになぜ信頼性が高い?再送制御・ACK・ストリーム・輻輳制御の仕組みをTCPとの違いから解説

通信プロトコル

QUICはUDPを基盤として動作するトランスポートプロトコルです。UDPにはTCPのような到達確認、再送、順序制御などが基本的に備わっていないため、「UDPを使っているのに、なぜQUICはWeb通信に必要な信頼性を実現できるのか」と疑問に感じるかもしれません。

ポイントは、QUICがUDPの信頼性に頼っているわけではなく、UDPの上にQUIC自身が信頼性を実現する仕組みを持っていることです。パケット番号、ACK、損失検出、再送に相当する処理、フロー制御、輻輳制御などをQUIC自身が担当します。

さらにQUICは、単純にTCPをUDP上で再現したものでもありません。複数の独立したストリーム、TLSとの統合、コネクションIDなどを取り入れ、HTTP/3のトランスポートとして利用できるよう設計されています。ここではIETFで標準化されたQUICの仕様を基に、その仕組みを順番に解説します。

そもそもUDPには何が足りないのか

UDP(User Datagram Protocol)は非常にシンプルなトランスポートプロトコルです。アプリケーションから渡されたデータをデータグラムとして送信しますが、相手へ必ず届くことを保証しません。

例えば、A・B・Cという3個のUDPデータグラムを送ったとしても、途中でBが失われる可能性があります。また、ネットワークの状況によって到着順が変化する可能性もあります。UDP自身は「Bがなくなったので再送してください」という高度な回復処理を行いません。

この単純さは欠点だけではありません。UDPはトランスポート層で複雑な接続管理を強制しないため、QUICのようなプロトコルが必要な機能をユーザー空間で構築するための土台として利用できます。

QUICはUDPの上に「信頼性の仕組み」を自分で実装している

QUICを理解するうえで最も重要なのは、UDPとQUICを同じものとして考えないことです。ネットワーク上ではQUICパケットがUDPデータグラムによって運ばれますが、通信の管理はQUIC層で行われます。

概念的には次のような階層になります。

HTTP/3
   ↓
QUIC
   ↓
UDP
   ↓
IP

UDPはQUICパケットを相手へ運ぶ役割を担当し、その上でQUICが接続管理、暗号化、ストリーム、損失回復、フロー制御などを担当します。

IETFのQUICトランスポート仕様はRFC 9000として標準化されています。RFC 9000: QUIC: A UDP-Based Multiplexed and Secure Transport[参照]

パケット番号によって届いたデータを管理する

QUICでは送信するパケットにパケット番号(Packet Number)が付けられます。この番号によって、受信側と送信側はどのパケットが送られ、どのパケットが受信されたのかを管理できます。

例えば概念的に、送信側がパケット番号100、101、102、103を順番に送ったとします。受信側で100、101、103が確認でき、102が確認できなければ、ネットワーク途中で102が失われた可能性を判断する材料になります。

QUICではパケット番号が再利用されないことも重要な特徴です。損失したパケットと、それに関連して後から送信されたデータを区別しやすい設計になっています。

ACKによって「どこまで届いたか」を送信側へ知らせる

信頼性を実現するもう一つの重要な仕組みがACK(Acknowledgement)です。受信側はACKフレームを利用して、受信したQUICパケットを送信側へ知らせます。

例えば送信側が複数のパケットを送り、受信側から「この範囲のパケットを受信した」というACKが戻れば、送信側は正常に届いたことを把握できます。

逆に、一定の条件を満たしてもACKされないパケットがあれば、QUICの損失検出アルゴリズムによってパケットロスと判断されることがあります。ACKと損失検出の詳細はRFC 9002で標準化されています。RFC 9002: QUIC Loss Detection and Congestion Control[参照]

パケットが失われると必要な情報を再送する

ネットワークではパケットロスが発生します。QUICはACKなどの情報を基に損失を検出すると、失われたパケットに含まれていた必要な情報を新しいパケットで再送できます。

ここでTCPとの違いとして覚えておきたいのが、QUICでは基本的に「同じQUICパケットそのもの」を再送するわけではないという点です。失われたパケットに含まれていた再送可能なフレームの情報を、新しいパケットへ入れて送信します。

新しいQUICパケットには新しいパケット番号が割り当てられます。例えばパケット102が失われた場合、その内容のうち必要な情報が後のパケット110などに入れられることがあります。「102番をそのままもう一度送る」という設計ではありません。

QUICではパケット番号とストリーム内の位置を分けて考える

QUICを理解するときにつまずきやすいのが、「パケットの順番」と「アプリケーションデータの順番」の違いです。

QUICにはSTREAMフレームがあり、そこにはストリームIDやデータのオフセットなどの情報を含められます。そのため、あるQUICパケットが失われ、そのデータが別の新しいパケットで送り直されたとしても、受信側は「このデータはストリーム内のどの位置に入るのか」を判断できます。

例えば、あるストリームで「ABCDE」というデータを送り、途中の「C」に相当する部分を運ぶパケットだけが失われたとします。後からその部分が別パケットで届けば、受信側はオフセットを基に正しい位置へ組み立てられます。

複数ストリームでTCPのHead-of-Line Blockingを改善する

QUICが単なる「UDP上のTCP」ではないことがよく分かる特徴が、複数ストリームの扱いです。1本のQUICコネクション内に複数の独立したストリームを持つことができます。

TCPはアプリケーションから見ると順序付けされた1本のバイトストリームです。そのためTCP上で多重化した複数の論理的な通信があっても、TCPパケットの損失によって後続データのアプリケーションへの引き渡しが待たされる問題があります。

QUICではストリームごとにデータの順序が管理されるため、あるストリームのデータが欠けても、別のストリームまで同じ理由でアプリケーションへの引き渡しを待つ必要はありません。

具体例:3つのWebリソースを受信する場合

例えばHTTP/3でWebページを表示するとき、複数のリクエスト・レスポンスがQUIC上で扱われます。あるストリームのデータがネットワークで失われても、別ストリームで必要なデータがそろっていれば、そちらの処理を進められます。

QUICは信頼性を捨てることでHead-of-Line Blockingを改善したのではなく、信頼性をストリーム単位で扱える設計にしたことがポイントです。

ただし、ネットワーク上のパケットロスそのものが無害になるわけではありません。パケットを失えば再送や輻輳制御などの影響は受けます。「QUICならパケットロスの影響が完全になくなる」という意味ではありません。

フロー制御で受信側の処理能力を超えないようにする

信頼性のある通信では、単に失われたデータを送り直せばよいわけではありません。送信側が高速にデータを送り続け、受信側が処理しきれなくなっても問題になります。

そこでQUICにはフロー制御があります。受信側が受け入れられるデータ量を送信側へ通知し、送信側が許可された範囲を超えて送信しないよう制御します。

QUICではコネクション全体に対するフロー制御と、個々のストリームに対するフロー制御があります。RFC 9000ではMAX_DATAやMAX_STREAM_DATAなどのフレームを用いる仕組みが規定されています。

輻輳制御でネットワークを圧迫しすぎないようにする

フロー制御が「受信側の処理能力」を考慮する仕組みなのに対して、輻輳制御(Congestion Control)はネットワークそのものの混雑を考慮する仕組みです。

大量のデータを際限なく送れば、ルーターなどのキューがあふれてパケットロスが増え、ネットワーク全体の性能を悪化させる可能性があります。そのためQUICにも輻輳制御が必要です。

RFC 9002ではQUICの損失検出と輻輳制御について規定されており、RTTの推定、輻輳ウィンドウ、ACK、パケットロスなどを利用して送信量を調整します。つまり、UDPを使っているからといって無制限にデータグラムを送り続けるわけではありません。

RTTを測定して損失検出の判断に利用する

パケットが少し遅れているだけなのか、本当に失われたのかを判断するには時間に関する情報も必要です。そのためQUICではRTT(Round-Trip Time:往復時間)を推定します。

送信したパケットに対するACKがどれくらいの時間で戻ってきたのかを測定し、ネットワークの往復遅延を推定します。この情報は損失検出やPTO(Probe Timeout)などに利用されます。

ネットワークの状態は一定ではありません。Wi-Fiの混雑やモバイル回線の状況などによってRTTは変化するため、QUICは実際の通信状況を観測しながら制御します。

QUICはTLS 1.3と統合され暗号化が基本になっている

QUICの特徴は信頼性だけではありません。現在標準化されているQUICではTLS 1.3を利用した暗号化がプロトコル設計へ組み込まれています。

QUICとTLSの利用方法についてはRFC 9001で規定されています。RFC 9001: Using TLS to Secure QUIC[参照]

TCPでHTTPSを利用する場合は、概念的にはTCP接続を確立し、その上でTLSのハンドシェイクを行います。QUICではトランスポートのハンドシェイクと暗号化の確立が密接に統合されており、接続確立に必要な待ち時間を抑えられるよう設計されています。

0-RTTなら再接続時にさらに早くデータを送れる場合がある

以前接続したことがある相手への再接続では、条件を満たせばQUIC/TLSの0-RTTを利用し、ハンドシェイク完了を待たずに一部のアプリケーションデータを送信できる場合があります。

ただし0-RTTデータにはリプレイ攻撃に関する特有のリスクがあります。そのため、どのようなデータでも無条件に0-RTTで送ってよいわけではありません。

この点でもQUICは「UDPだから速い」という単純なプロトコルではありません。接続確立、暗号化、再接続などを含めて遅延を減らすよう設計されています。

コネクションIDによってIPアドレスが変わっても接続を識別できる

TCP接続は一般に送信元・宛先のIPアドレスとポート番号などによって識別されます。スマートフォンがWi-Fiからモバイル回線へ切り替わるとIPアドレスが変化することがあり、従来の接続維持には不都合が生じます。

QUICにはConnection ID(コネクションID)という仕組みがあります。QUICエンドポイントはIPアドレスやUDPポートだけに依存せず、コネクションIDを利用して接続を識別できます。

そのため適切な条件下では、クライアントのネットワーク経路が変化した場合に接続を移行できる設計になっています。これは特に無線ネットワークを移動する端末で有用です。

TCPとQUICの信頼性を比較するとどう違う?

TCPとQUICは実装方法こそ異なりますが、アプリケーションへ信頼性のあるデータ転送を提供するという点では共通部分があります。一方、QUICではその仕組みをUDP上で新しく設計し直しています。

機能 TCP QUIC
基盤 IP上のTCP UDP上のQUIC
到達確認 ACKを使用 ACKフレームを使用
損失回復 TCPが担当 QUICが担当
順序管理 1本のバイトストリーム ストリームごとに管理
フロー制御 あり コネクション・ストリーム単位であり
輻輳制御 あり あり
暗号化 TCP自体には含まれず、通常TLSを上位で利用 TLS 1.3をプロトコルへ統合
多重化 TCP自体には独立ストリーム機能なし 複数ストリームを標準で提供
接続識別 IPアドレス・ポートなど Connection IDを利用

この比較から分かるように、QUICはUDPの「届くかどうか分からない」という性質をそのままアプリケーションへ見せているわけではありません。

では、なぜ最初からTCPを使わずUDP上に作ったのか

「結局QUIC側で再送や輻輳制御を実装するなら、最初からTCPを使えばよいのでは」と感じるかもしれません。しかしTCPはOSのカーネルなどに実装され、インターネット上のさまざまなミドルボックスもTCPの既存動作を前提としているため、大幅なプロトコル変更を世界規模で普及させることは容易ではありません。

UDPはすでに広く利用できるトランスポートであり、その上でQUICをユーザー空間に実装することで、OSのTCPスタック自体を変更する場合より新しい機能を展開しやすいという利点があります。

ただし「UDPなら必ずファイアウォールを通過できる」という意味ではありません。ネットワークによってはUDPやQUICが制限されることもあります。QUICはUDPを利用することで既存インターネット上へ新しいトランスポート機能を展開しやすくした、と理解するとよいでしょう。

HTTP/3はQUICをトランスポートとして利用する

QUICを現在のWebで身近なものにしているのがHTTP/3です。HTTP/3はTCPではなくQUICを利用します。

HTTP/3についてはRFC 9114で標準化されています。RFC 9114: HTTP/3[参照]

HTTP/2でも1本の接続上で複数リクエストを多重化できますが、トランスポートとしてTCPを利用するため、TCPレベルでパケットが失われると、その欠落部分が回復するまで後続のデータをアプリケーションへ渡せない問題があります。HTTP/3ではQUICの独立したストリームを利用することで、このトランスポート層のHead-of-Line Blockingを軽減しています。

「UDP=信頼性なし、QUIC=信頼性あり」は矛盾しない

ここまでの仕組みを理解すると、「UDPなのに信頼性がある」という表現が矛盾していないことが分かります。

UDPそのものにはTCP型の信頼性保証がありません。しかし、UDPを利用するアプリケーションや上位プロトコルが独自に信頼性を実装することは禁止されていません。QUICはまさにその方法を採用しています。

たとえるなら、UDPは「荷物を運ぶが、到着確認まではしてくれない配送手段」です。QUICはその配送手段を利用しながら、荷物に管理番号を付け、受取確認を取り、届かなかった中身を送り直し、混雑状況に応じて発送量を調整する独自の管理システムを構築している、と考えるとイメージしやすいでしょう。

まとめ|QUICの信頼性はUDPではなくQUIC自身が実現している

QUICがUDPを基盤にしながらTCPに似た信頼性のある通信を実現できる最大の理由は、UDPに足りない機能をQUIC自身が実装しているからです。

QUICはパケット番号とACKによって受信状況を把握し、損失を検出すれば必要な情報を新しいパケットで送り直します。さらに、ストリームごとの順序管理、フロー制御、輻輳制御、RTT推定と損失検出などを組み合わせ、信頼性のあるデータ転送を実現しています。

その一方で、QUICはTCPを単純にUDP上へ移植したものではありません。独立した複数ストリーム、TLS 1.3との統合、Connection IDによる接続管理など、現代のWeb通信を意識した仕組みが導入されています。

したがって、QUICを理解するときは「UDPだから高速だが信頼性が低い」と考えるのではなく、「UDPをパケットの運搬手段として利用し、その上にQUIC独自の信頼性・セキュリティ・多重化機構を構築している」と捉えるのが最も分かりやすいでしょう。

コメント

タイトルとURLをコピーしました