HTTPプロトコルの進化
安全な土管(TCP+TLS)が開通したら、いよいよWebページの中身を要求します。ここで使用されるHTTPプロトコルは、Webの歴史そのものであり、バージョンごとに劇的な進化を遂げてきました。
4.1 プロトコルバージョンの交渉 (ALPN)
ブラウザはサーバーがどのHTTPバージョンに対応しているかを知りません。そこで、TLSハンドシェイクの中に ALPN (Application-Layer Protocol Negotiation) という拡張情報を含めます。「私は h2 (HTTP/2) と http/1.1 が話せます」とクライアントが提示し、サーバーが「では h2 で話しましょう」と選択します。
4.2 HTTP/1.1 から HTTP/2 への飛躍
HTTP/1.1 の課題:Head-of-Line Blocking
従来のHTTP/1.1はテキストベースのプロトコルで、原則として「1つのリクエストが終わるまで次のリクエストを送れない」という制約がありました(パイプライン化はありましたが普及しませんでした)。これを Head-of-Line (HoL) Blocking と呼びます。
例えば、先頭の大きな画像のダウンロードが詰まると、後続の小さなCSSやJSもすべて待たされてしまいます。これを回避するため、ブラウザは1つのドメインに対して最大6本のTCP接続を同時並行で張るという力技を使っていました。
HTTP/2 の解決策:マルチプレクシング
HTTP/2はバイナリベースのプロトコルに刷新され、ストリームという概念を導入しました。1本のTCP接続の中に、仮想的な複数の通信路(ストリーム)を作り、パケット(フレーム)単位でデータを細切れにして送受信します。
これにより、巨大な画像データの合間にCSSデータのフレームを割り込ませるような マルチプレクシング(多重化) が可能になり、HTTPレベルでのHoLブロッキングは解消されました。また、HPACKによるヘッダー圧縮も導入され、転送効率が大幅に向上しました。
4.3 HTTP/3 と QUIC
しかし、HTTP/2にも弱点がありました。それは土台となっているTCPの抱えるHoLブロッキングです。TCPはパケットの順序を厳密に保証するため、1つのパケットがネットワーク上で消失すると、それが再送されて届くまで、後続のすべてのパケット(全く関係ない別ストリームのデータであっても)の処理をOSレベルで止めてしまいます。
これを解決するためにGoogle等が開発し、標準化されたのが HTTP/3 です。
- UDPベースのQUICプロトコル: TCPを捨て、UDPを採用しました。UDPは順序保証などをしないシンプルなプロトコルですが、その上にQUICという層を作り、ユーザー空間(アプリケーションレベル)で信頼性を再実装しました
- 真の独立ストリーム: QUICではストリームごとにパケットロス制御が独立しています。あるストリームのパケットが消えても、他のストリームは影響を受けずに処理を続けられます
- コネクションマイグレーション: TCPはIPアドレスが変わると切断されますが、QUICはコネクションIDで接続を識別するため、Wi-Fiから4Gに切り替わっても通信が途切れません
HTTP/3への接続は、通常 Alt-Svc ヘッダーを通じて行われます。最初の接続はHTTP/2などで行い、サーバーが「次はUDPポート443のHTTP/3で来てね」と伝え、ブラウザが次回の通信から切り替えるというステップを踏みます。