HTTP/1.1 vs 2 vs 3 — 詰まりをどこまで外せたか
1枚のWebページは、HTML・CSS・JS・画像と何十個ものファイルでできています。HTTPのバージョンが上がってきたのは、この「大量の小さいファイルを、いかに待たせずに取ってくるか」という一点を解くためでした。
答えの変遷はシンプルです。HTTP/1.1 は回線を何本も並べて、HTTP/2 は1本にまとめて同時に流し、HTTP/3 はTCPそのものをやめました。なぜ最後の一手が必要だったのか――下の図1でパケットを1つ落として比べてみてください。
HTTP/2 の多重化と、その足元にあるTCP
HTTP/1.1 の弱点は、1本の接続で1つずつしか処理できないことでした。先頭のリクエストが終わるまで後ろが待たされる――これをHTTPレベルのHoLブロッキングと呼びます。ブラウザは苦肉の策として接続を6本まで並べてしのぎましたが、7個目以降は結局順番待ちです。
HTTP/2 はここを多重化(ストリーム)で解きました。1本の接続の中にリクエストごとの仮想的な通り道を作り、全部を同時に流す。接続も1本で済むので、ハンドシェイクの往復も1回で終わります。図1でロスなしのレースを走らせると、HTTP/1.1 との差が一目で分かります。
ところが問題が残りました。ストリームを分けたのはHTTPの中だけで、その下を流れるTCPから見ればただ1本の連続したバイト列です。TCPは「順番どおりに渡す」ことを保証するので、途中のパケットが1つ落ちると、その後ろに届いた分をすべて足止めして待ちます。結果、無関係なストリームまで巻き添えで止まる。これがTCPレベルのHoLブロッキングで、図1で全12本が同時に赤くなる現象の正体です。
HTTP/3 は、TCPを使うのをやめた
HoLブロッキングの原因がTCPそのものなら、TCPを使わなければいい――という思い切った答えが HTTP/3 です。土台に QUIC という新しいプロトコルを据え、それをUDPの上に実装しました。
QUICはストリームの存在を自分で知っているので、「どのストリームのパケットが落ちたか」を区別できます。落ちたストリームだけを止め、他のストリームはそのまま渡す。図1で HTTP/3 が1本だけ赤くなるのは、このためです。さらに暗号化(TLS)を最初から組み込んだ設計なので、接続確立の往復も減っています。図1でレース開始直後、HTTP/3 だけ一足先に走り出すのがそれです。
- Keep-Alive
- 1回作った接続を使い回す仕組み。HTTP/1.1で標準になり、毎回の接続確立を省いた。
- 多重化
- 1本の接続の中に複数のストリームを作り、同時にやりとりすること。HTTP/2の中核。
- HoLブロッキング
- 先頭が詰まると後続が全部待たされる状態。HTTP/1.1ではリクエスト単位、HTTP/2ではTCP単位で起きる。
- QUIC
- UDPの上に作られた新しい転送プロトコル。ストリームを認識し、TLSを内蔵する。
- 0-RTT / 1-RTT
- 接続確立に必要な往復回数。QUICは暗号化込みで1往復、再接続なら0往復で始められる。
まとめ
HTTPの進化は「詰まりをどこまで取り除けるか」の歴史です。HTTP/1.1 は接続を増やして、HTTP/2 は1本の中で多重化して、HTTP/3 は詰まりの原因だったTCPごと置き換えて解決しました。効果が最も出るのは、小さいファイルが多く、回線が不安定なとき――つまりモバイル回線です。安定した高速回線では体感差が小さいので、「新しいから速い」ではなく「どの詰まりを外したのか」で理解するのが正確です。