え! QUIC無効化するの? HTTP over QUIC or TCPの接続選択を考える

Jun-ya Kato
nttlabs
Published in
13 min readJul 6, 2021

--

図1: QUICの無効化は待ってください

QUICを無効化?!

“Googleが遅く感じるので、QUICを無効化する” そのようなTIPSが散見されます。数年前から見ていましたが、QUICがトレンドになったのと同時に、再び目立ち始めたと感じています。IPv6が普及し始めた時期もそうでしたが、新しいプロトコルの出現時には、決まって現れる文言です。

問題に直面する利用者にとっては切実であり、無効化は間違った解決手段とは言いません。しかしエンジニアならば無効化する前に、原因を探求しなければなりません。

HTTP3/QUIC と HTTP2/TCP どちらが優先?

QUICの無効化とは、TCPだけを利用する選択と言えます。はじめにQUIC, TCPの両者が使えるとき、どのように使い分けるのか見ていきます。

ある、HTTPSスキームのURL

https://www.example.com/

があったとき、HTTPバージョンとトランスポートプロトコルは

  • HTTP/3 + QUICトランスポートの場合
    1. h3 over QUIC
    2. h3–29 over QUIC
  • TCPトランスポートの場合
    3. h2 over TLS/TCP
    4. spdy/3.1 over TLS/TCP
    5. http/1.1 over TLS/TCP

一例を挙げると、上記の1.〜5. ような複数の組み合わせが考えられます。実際は、組み合わせはさらに多くあるでしょう。しかしURLをみてもHTTPのバージョンもトランスポートプロトコルも判別できる情報は含まれていません。

では、ブラウザはどの順序で接続すればよいでしょうか? サーバが対応している前提で、通常、より高性能な仕組みが使いたいと思いますので、クライアントは 1.〜5. の優先順位で使いたくなります。

いまどき、こんな単純な動作をするブラウザは存在しないと思いますが、愚直に、HTTP3/QUIC → HTTP2/TLS/TCP と逐次接続したと仮定すると、

  1. HTTP3/QUICでの接続を試して、OKなら良し!
  2. 試した結果NGなら、次はHTTP2/TLS/TCPでの接続を試す。

step 1. でサーバがHTTP3/QUICに対応していないとNGが判定されるまでの時間は接続遅延となります。サーバがUDP/443を利用不可であることを ICMP Destination Unreachable (Port Unreachable)を使って通知する仕組みがありますが、ICMPメッセージが経路途中で廃棄されてしまい、クライアントにおいては接続タイムアウト待ちが生じることも少なくありません。

次に考えられる手法として、

  • HTTP3/QUIC接続と同時に、もしくはわずかな差で、HTTP2/TLS/TCPの接続試す
  • 先につながったほうを使う

とすれば、サーバがHTTP3/QUICに未対応であっても最小の接続遅延でコンテンツにアクセスすることができます。異なる通信手段の並行で動作させて最適なものを選ぶ、いわゆる Happy Eyeballs (RFC8305) に類する手法です。

Google Chromeの動きを観察してみる

Google Chrome (version 91.0.4472.124) の実装がのようになっているか調べてみます。動きを見るために、2つの拡張機能を組み込みました。

  1. HTTP indicator
  2. HTTP/2 and SPDY indicator ← HTTP/3にも対応しています

どちらも閲覧しているページのHTTPバージョンを表示してくれます。2つ組み込んだのは拡張機能が正しく動いているか確認するためです。なお拡張機能を組み込まなくてもChrome標準搭載のデベロッパーツールで調べることも可能です。次に、図2にあるGoogle Chromeの設定画面chrome://flags を開き、明示的にQUICの利用をEnabledとしておきます。

図2: QUIC protocol と HTTPSSVC を明示的に有効化(Enabled)する

ここまで準備ができたら、実際にHTTP/3対応サイトにアクセスし、どのような挙動を示すか観察してみます。Googleのサービスは特別扱いされている可能性を考え、Cloudflareのblog (blog.cloudflare.com)へアクセスをターゲットとしました。ちなみに、この記事を掲載するmediumも、執筆時点ではCloudflareが配信するコンテンツのため同じ挙動を示します。

blog.cloudflare.comへの初回アクセスでは、HTTP indicatorはHTTP2/TLS/TCP による接続を示しました(図3)。

図3: Cloudflare blogにHTTP/2で接続した様子

次回以降のアクセスからは図4の画面にある通り、HTTP indicator はHTTP3/QUIC (h3–29)による接続を示しました。

図4: Cloudflare blogにHTTP/3 over QUICで接続した様子

Google Chromeと blog.cloudflare.com 間とのパケットをダンプして解析してみると、下記の順序となっています。

  1. まずHTTP2/TLS/TCPで接続を開始している。
  2. 少し遅れてHTTP3/QUICを使い始める。複数の接続がある場合は、HTTP2/TLS/TCP, HTTP3/QUICを併用する状態となる。
  3. 以降はHTTP3/QUICを使い続ける。

HTTP/3対応を通知する Alt-SVC

初回アクセスで使われたHTTP2/TLS/TCPから、HTTP3/QUICによるアクセスへ切り替わる過程はどのような仕組みでしょうか? HTTPには利用可能なサービスを通知するAlt-SVC (RFC7838) という仕組みがあります。curlを使いHTTP2/TLS/TCPでアクセスしてヘッダを見ると、

# curl --http2 -v -I https://blog.cloudflare.com/
.
.
server: cloudflare
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400,
h3-29=":443"; ma=86400, h3=":443"; ma=86400
h3 は HTTP/3 over QUICv1 を表すバージョン、h3-27h3-29 は標準化直前のインターネットドラフトに基づくバージョンです。

alt-svc ヘッダによりクライアントは blog.cloudflare.com ではHTTP3/QUIC (UDPポート443) にてサービスの待ち受けていることを知ることができ、以降のアクセスでHTTP3/QUICを使うことができるようになります。

HTTP/2 → HTTP/3 の順でプロトコルを切り替えており無駄なオーバヘッドがあるように感じます。しかし現時点では、HTTP/3未対応サーバがより多く存在するので、初回の接続だけはHTTP/2を使うGoogle Chromeの挙動は接続遅延を生じさせない観点から合理的と言えます。

DNSを使った利用可能HTTPバージョン通知 (DNS SVCB and HTTPS RRs)

HTTPやトランスポートプロトコルのアウトバンドで、サーバがHTTP/3に対応していることをDNSを使って通知する仕組みがあります。名前解決の段階で利用可能なHTTPのバージョンを知ることができるのが利点です。IETFの過去の議論では、DNS SRVリソースレコード(RR)の利用が検討されていましたが、現在はSVCBとHTTPS RRの利用が有力になっています。HTTP2/TLS/TCPで接続してAlt-SVC情報を読み取るオーバヘッドがなく、初期接続からHTTP3/QUICを用いた接続を試行することができます。TLS1.3/TCPでもフルハンドシェイク時は2-RTT必要なコネクション開設が不要となり初期接続のレイテンシ削減ができます。

今回紹介した、Google Chrome (version 91.0.4472.124)ではExperimental機能として実装されており、前述の図2の二つ目の設定項目に現れています。また、AppleがWWDC2021で発表した内容によると、macOS 12 MontereyやiOS 15で実装することが言及されています(図5)。コンテンツ配信側のCDNの例を挙げると、すでにCloudflareでは利用が始まっています。

図5: AppleからHTTPSSVCがmacOS 12 Monterey, iOS15に実装される言及(@WWDC2021)

HTTP3/QUIC, HTTP2/TLS/TCP 使い分けまとめ

HTTP3/QUICとHTTP2/TLS/TCPの使い分けについては、ブラウザの実装において、両者の使い分けによる問題が生じないよう十分な配慮がされつつ、利用可能であればHTTP3/QUICの恩恵を受けられる状況がかなり出来上がりつつあると考えます。

QUICとNATの(おそらく小さな)問題

本稿の本題からそれますが、最近、QUICがNA(P)Tルータのセッションテーブルを枯渇させる問題が話題になっていました。筆者は大きな問題になるとは考えていませんが、運悪く本事象に遭遇したユーザにとっては、“QUICを無効化したくなる状況” には違いないので、最後に言及しておきます。

NA(P)TルータはTCPコネクションに対しては、FINやRST信号を見て終了を判断し、テーブルから状態の消去をすみやかに行いますが、QUICでは終了判定ができないためタイムアウトを待ち消去することになります。特にUDPの接続状態の保持タイマが長めに設定される装置では、状態が蓄積しがちとなります。セッションテーブルがあふれるとパケット転送が停止したり、装置にバグがあればクラッシュを招くこともあるかもしれません。過去に使っていたあるルータでそのような事象を経験したことがあります。しかしすでに対処された事象であり、現在利用している同社のルータでは全く問題は感じていません。

以下は推測の範囲ですが、NA(P)Tテーブルの枯渇の事象はQUIC仕様の問題ではなく、セッションの上限数が十分でない古いルータや、メモリと電池が厳しいモバイルルータの利用、もしくはルータの能力に見合わない端末の収容設計の問題ではないかと考えています。

ある話題の中で参照されていた、ヤマハ社のRTX830の仕様RTX1220の仕様ではNA(P)Tセッション数は、65534となっていました。TCP, UDP, ICMP合算値だと思います。 IPv4/IPv6それぞれで分計か合算かは記載がありませんでした。また、UDPの接続状態保持タイマのデフォルト値は900秒だそうです。65534では不足する利用形態があるのか筆者には想像がつきませんが。もしかするとエンタープライズ利用を想像すると、大量の端末を抱え、かつ、Google Workspace だけでなく、将来Office 365 など企業が利用するWebサービスの多くがHTTP/3対応する状況が来れば、NA(P)Tルータのセッション上限数が問題になるかもしれません。正確な試算に基づくものではないので、あくまでも推測です。

コネクションの考え方の見直しとミドルボックス

従来から存在した、NA(P)Tルータ、FW/IDS/IPS, DPI, ロードバランサなどミドルボックスと呼ばれる装置では、コネクションを5タプル(プロトコル, src/dstアドレス, src/dstポート)を使って識別していましたが、QUICプロトコルではコネクションの概念をコネクションID (CID) によって識別します。さらにTCP/UDPにはないQUICプロトコルの特徴として、UDP/IPのレイヤのsrc/dst両IPアドレスやポート番号が変化しても接続を維持できるコネクションマイグレーションの仕組みが標準で組み込まれています。従来のTCP/UDPのコネクションの識別と、QUICのコネクションの識別には異なる考え方が必要となります。

QUICはE2Eの暗号化が必須なのでミドルボックスが介入できる範囲は小さいはずです。しかし、CIDなどのQUICレイヤの情報や、他の入手可能な情報を併用して何らかの制御を行う “QUIC対応装置” が出現する可能性は高いと思います。E2Eのプロトコル処理に不用意に介入するミドルボックスは、新しいプロトコルのデプロイを阻害する、いわゆる “硬直化” を引き起こす根深い問題です。遠い将来に、QUICに置き換わるプロトコルが出現するかもしれません。しかし “QUIC対応装置” でデプロイが阻害されては元も子もありません。現在のQUICも、そのような状況を想定して検討されています。なお、QUICがUDPの上に構築されているのは、現在のインターネットではNA(P)Tルータの存在を排除できない、やむを得ない事情もあります。硬直化についてリンクした先の資料はcURL開発者のDaniel Stenberg氏による詳細な解説で参照する価値のあるものです。

最後に

NTT研究所では、ハイパフォーマンスなWebサービスを生み出すことに関心のある仲間を募っています。

--

--