HTTP/2とHTTP/3は何を変えたのか

HTTP/2とHTTP/3は、HTTPのメソッドやステータスコードを大きく変えずに、メッセージの運び方を改善したプロトコルです。
中心となる違いは、多重化する場所です。
- HTTP/2は、1本のTCP接続上に複数のHTTPストリームを多重化する
- HTTP/3は、QUIC接続上の複数ストリームへHTTPを対応付ける
「新しいバージョンなら必ず高速」という意味ではありません。遅延、パケット損失、CDN、キャッシュ、コンテンツ構成によって結果は変わります。
先に比較
| 観点 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 主なトランスポート | TCP | TCP | QUIC(通常UDP上) |
| 1接続内の並行処理 | 応答順序の制約がある | 複数ストリーム | 複数QUICストリーム |
| ヘッダー圧縮 | なし | HPACK | QPACK |
| 暗号化 | HTTP仕様上は必須ではない | 仕様上は必須ではない | QUICにTLS 1.3を統合 |
| パケット損失の影響 | TCP接続内で共有 | 複数HTTPストリームへ及び得る | 別ストリームの配送待ちを避けやすい |
ブラウザで使うHTTP/2は事実上HTTPSが前提ですが、HTTP/2仕様そのものはTLSを必須としていません。一方、HTTP/3のQUICハンドシェイクにはTLS 1.3が統合されています。
HTTP/1.1で起きる待ち
HTTP/1.1では持続的接続を使えますが、同じ接続上で複数の応答を自由に交差させられません。パイプライン化も定義されましたが、先の応答が遅いと後ろが待つ問題や実装上の難しさがあり、ブラウザでは広く活用されませんでした。
そのため、ブラウザは同じオリジンへ複数のTCP接続を使って並行性を補うことがあります。ただし、接続数はブラウザ、通信状況、プロキシ、オリジンによって変わります。「常に6本」などの固定値として設計してはいけません。
Connection A: HTML ───── CSS
Connection B: JS ───────────
Connection C: Image ─────────
接続が増えると並行処理はできますが、それぞれに接続確立、輻輳制御、TLSなどのコストがあります。
HTTP/2:HTTPストリームをTCP上で多重化
HTTP/2はHTTPメッセージをバイナリのフレームへ分け、ストリームIDを付けて1本の接続上で交互に運びます。
TCP connection
├─ Stream 1: HTML frames
├─ Stream 3: CSS frames
└─ Stream 5: image frames
あるHTTP応答の完了を待たず、別の応答フレームを送れることが利点です。さらにHPACKで、繰り返し現れるHTTPヘッダーを圧縮します。
TCPレベルのHead-of-Line Blocking
TCPは、1本の順序付きバイト列を確実に届けます。途中のTCPセグメントが失われると、後続データを受信していても、欠けた部分が再送されるまでアプリケーションへ順番に渡せません。
HTTP/2のストリームは同じTCP接続を共有するため、1つのパケット損失が複数ストリームの配送待ちにつながることがあります。これはHTTP/2のフレーム多重化だけでは解消できません。
HTTP/3:QUICストリーム上で多重化
HTTP/3は、TCPではなくQUICへHTTPの意味を対応付けます。QUICは通常UDP上で動作し、暗号化と複数のストリームをトランスポート側で扱います。
各QUICストリームは、それぞれの中では信頼性と順序を保ちます。あるストリームのデータが失われても、その再送待ちによって無関係なストリームのデータまでアプリケーションへ渡せなくなることを避けられます。
ただし、完全に独立しているわけではありません。
- 接続全体の帯域と輻輳制御は共有する
- パケット損失が増えれば、接続全体の送信速度へ影響し得る
- サーバー、端末、暗号処理のCPU負荷も性能へ影響する
したがって、HTTP/3は「損失があっても他のストリームがTCPの順序待ちに巻き込まれない」と理解するのが正確です。
QPACK
HTTP/3はヘッダー圧縮にQPACKを使います。HTTP/2のHPACKをQUICの複数ストリームへそのまま適用すると、ヘッダー復元の順序待ちが問題になります。QPACKは、QUIC上でその待ちを制御できるように設計されています。
接続とフォールバック
HTTPSでHTTP/2を使う場合、TLSのALPNでクライアントとサーバーがh2などを合意します。
HTTP/3は、既存のHTTPS接続で受け取ったAlt-Svcヘッダーなどを通じて利用可能と知る場合があります。その後、クライアントはQUICでの接続を試します。
Alt-Svc: h3=":443"
ネットワークや中継機器がUDPを通さない場合、クライアントはHTTP/2やHTTP/1.1を使える必要があります。HTTP/3対応は、フォールバックをなくすことではありません。
再接続では、条件が整えばQUICの接続確立を短縮できる場合があります。ただし0-RTTデータには再送リスクがあるため、状態変更を伴う操作へ安易に使わない点はTLSと同じです。
優先度は固定された順番ではない
ブラウザは、HTML、CSS、JavaScript、画像などの重要度を考えて送信順を調整します。しかし、具体的な判断はブラウザとサーバーの実装、HTML属性、ネットワーク状態で変わります。
HTTP/2の初期仕様にあった依存ツリー方式の優先度は、現在のRFC 9113では非推奨です。代わりにRFC 9218のExtensible PrioritiesがHTTP/2とHTTP/3で利用できますが、対応と挙動は実装ごとに確認が必要です。
そのため、「HTTP/2ではCSSが必ず最優先」のような固定ルールとして説明することはできません。preload、fetchpriority、不要なリソース削減なども含め、ブラウザのNetworkパネルで確認します。
Server Pushを前提にしない
HTTP/2には、クライアントが要求する前にリソースを送るServer Pushがあります。しかし、キャッシュ済みデータとの重複や優先度調整が難しく、ブラウザの対応状況も変化しています。
新しい設計ではServer Pushを前提にせず、通常のキャッシュ、preload、CDN配信を先に検討します。HTTP/3仕様ではPushの仕組みがありますが、利用価値は対応クライアントと実測で判断します。
正しく比較する測定条件
HTTPバージョンの効果を測るときは、次をそろえます。
- 実際に合意されたプロトコルを確認する
- ブラウザキャッシュとCDNキャッシュの有無を分ける
- 初回接続と再接続を分ける
- RTT、帯域、パケット損失率を記録する
- オリジン、CDN、TLS設定を同じにする
- リソース数、サイズ、圧縮方式を同じにする
- 1回ではなく複数回測り、ばらつきを見る
Chrome DevToolsではNetworkパネルのProtocol列で、http/1.1、h2、h3などを確認できます。表示名はブラウザによって異なります。
コマンドで確認する場合も、利用中のcurlがHTTP/2またはHTTP/3に対応している必要があります。
curl -I --http2 https://example.com/
curl -I --http3 https://example.com/
まとめ
- HTTP/2は、複数のHTTPストリームを1本のTCP接続上で多重化する
- HTTP/3は、HTTPをQUICの複数ストリームへ対応付ける
- HTTP/2では、TCPの再送待ちが複数ストリームへ影響し得る
- HTTP/3では、損失したストリームの順序待ちを他のストリームから分離できる
- HTTP/1.1の接続数や優先順位を固定値として扱わない
- HTTP/3が使えないネットワークでは、HTTP/2などへ戻れる構成が必要
- 性能はプロトコル名だけで判断せず、同じ条件で実測する
参考リソース
- RFC 9113 - HTTP/2
- RFC 9114 - HTTP/3
- RFC 9000 - QUIC: A UDP-Based Multiplexed and Secure Transport
- RFC 9204 - QPACK: Field Compression for HTTP/3
- RFC 9218 - Extensible Prioritization Scheme for HTTP