プライム・ストラテジー「KUSANAGI」の開発チームの石川です。
「KUSANAGI」はWordPressをはじめとするCMSを高速に動作させる世界最速クラスの仮想マシンです。わたしたちは「KUSANAGI」を開発して皆様にご利用いただくほか、お客様のウェブサイトを「KUSANAGI」で運用しています。
この連載では、「KUSANAGI」の開発やお客様とのお話の中で感じた課題や実際の運用の中で得た知見などをお伝えしています。
今回は次世代のHTTPとも呼ばれる「HTTP/3」の裏側で使われている「QUIC(クイック)」についてお話ししたいと思います。
Googleが通信パフォーマンス改善について追求した「QUIC」
QUICはもともとGoogleによって設計されたトランスポート層の通信プロトコルです。
Googleがプロトコルを開発することを意外に思う人がいるかもしれませんが、Googleは検索エンジンだけでなく、ウェブのパフォーマンスを上げるテクノロジーに注力しています。この記事でも紹介されている「Core Web Vitals」や軽量な画像フォーマット「WebP」などはブラウザーを介してウェブパフォーマンスを上げるテクノロジーの代表例です。
そのGoogleがインターネット上でのウェブ(HTTP)の通信のパフォーマンスをどうしたら改善できるか、という点を追求した結果がこのQUIC (RFC 9000) です。
ここでちょっとだけネットワークの基礎のおさらいをしたいと思います。
OSI参照モデルではプロトコルは「アプリケーション層」「プレゼンテーション層」「セッション層」「トランスポート層」「ネットワーク層」「データリンク層」「物理層」の7つのレイヤーで構成されます。(筆者は基本情報処理資格で あぷせとねでふ と覚えました)
私達が今使っているHTTPプロトコル(HTTP/1.1およびHTTP/2)は「アプリケーション層」のプロトコルです。そして、このHTTPはTCP(トランスポート層)IP(ネットワーク層)の上で動作しています。
冒頭でQUICは「トランスポート層」の通信プロトコルと書きました。HTTP/3とQUICは同じではありません。HTTP/3は「アプリケーション層」のプロトコルで、QUIC(トランスポート層)の上で動作するのです。
ここで、HTTP/3は乱暴に言うとTCPをQUICで置き換えたものというイメージを掴んでもらえると思います。
TCPとUDP、2つのプロトコルの違いとは?
IP(ネットワーク層)で使われる「トランスポート層」にはTCPとUDPの2つのプロトコルがあります。現在インターネット上で使われているプロトコルの多くはTCPですが、DNSやNFSなどUDPを使うプロトコルもあります。この2つのプロトコルの違いは何でしょうか?
TCP(Transmission Control Protocol)はIPネットワークでリモートと信頼性の高い通信を提供するために設計されたプロトコルで、高い信頼性を実現する機能を持つのがTCPの特徴です。具体的には、順番保証、再送、誤り検知、フロー制御、輻輳制御などです。一方で、UDP(User Datagram Protocol)はIPネットワークでリモートと最小のオーバーヘッドで通信するように設計されています。
UDPはデータロス等が許容されるアプリケーションや通信性能が要求される場合に使用されています。逆に言うと、TCPは信頼性を確保するために性能を犠牲にしていると言えるわけです。特にウェブが発達した近年で問題となっています。通信量の増加やデータリンク層で切断が発生するモバイルネットワークでは、しばしばパケットが途中で破棄や配送遅延が起こります。TCPはプロトコルレベルでデータの送達確認や再送を行なって、これらの障害を修復しようとします。これはとても有り難いことなのですが、この送達確認や再送が輻輳を招き、逆に通信のパフォーマンスを大きく下げることもあるのです。これがTCPで動作するHTTPの課題でした。
HTTPの歴史とTLS
話は少し変わりますが、HTTPプロトコルには1.0、1.1、2、3とあります。HTTPそのものも、遅延を減らすために工夫をして進化してきました。
当初のHTTPは1回の通信でデータをやりとりして終了するものでした。しかし、1つのウェブサイトを表示するためにHTMLだけでなくリソース(CSS、JS、画像など)を利用するようになったり、短い時間の間に別のページへジャンプしたりするようになり、毎回コネクションを張るオーバーヘッドが無駄になるようになりました。そこで登場したのがkeep-aliveです。サーバサイドでコネクションを維持しておき、再利用することで以後コネクションを確立する処理を省略できるようになりました。
この考えを進化させたのがHTTP/2です。コネクションの再利用に加えて接続の多重化やパイプラインを実現しました。しかし、TCPの上で動作する以上はTCPによるパケットの破棄や遅延は避けられず、限界が生じてしまいました。
また、近年はHTTPをTLS(Transport Layer Security、SSL(Secure Sockets Layer)と呼ぶこともある)でラップしたHTTPSで行うことが一般的になってきました。TLSでは接続先の正当性を証明書で評価する、通信を暗号化するための鍵を交換するといった処理が行なわれます。このため、従来のHTTPによるコネクション確立の処理よりもオーバーヘッドが大きくなっています。このTLSの処理自体も当然TCPで行なわれるので、TCPの性能の影響を受けます。TLSは暗号化を行う都合上、TCPが持つ障害を修復する処理(破損したデータの破棄など)と被る部分もありました。
HTTPの限界を克服するために登場したQUIC
このように広く普及したHTTPとその下のTCPの限界を克服するために考案されたのがQUICです。QUICはUDPをベースに多重化することを前提に、コネクションの確立に必要な処理を極力減らすように設計されています。UDPをベースにしているため、ファイアウォールなどではUDPを許可する必要があります。また、TCPよりもパケットの損失を減らす優れた方法を取り入れ、パケットの再送を改善しています。興味深いものとしてはIPアドレスが変わってもコネクションを維持できる点です。モバイルネットワークなどで端末が移動することで割り振られたIPアドレスが変わったとしても、コネクションの確立を再度やり直さないで済みます。このように、ここまで説明してきたTCPとHTTP、TLSの弱点を補うように設計されているのです。
QUICはHTTP/3で使うことを目的にしていますが、理論上は他のアプリケーション層のプロトコルで使うことができます。またWebSocketやREST APIのようにHTTPで動作するプロトコルならば、そのまま恩恵を受けられるでしょう。
QUICによりウェブブラウジングが速くなるといったユーザー目線での体感の恩恵はもちろんですが、パケットの再送などで生じていた無駄なトラフィックが減少することで相対的にHTTPによる通信負荷を減らすことにつながると考えられます。ユーザーとしても通信量(いわゆるギガ)が多少は減るかもしれません。
QUICの普及状況ですが、ブラウザーに関しては最新のChrome、Firefoxではサポート済みです。Safariではまだ有効にはなっていないようです。
一方でサーバー側まちまちです。LightSpeed が一早くHTTP/3をサポートしています。しかし、KUSANAGIでも採用しているNginxでは別のブランチで開発が進められていますが、まだ正式にはサポートされていません。また、Apache HTTPDもサポートしていません。他にはCaddyが実験的にサポートしています。
ウェブサーバーのシェアの半分をNginxとApache HTTPDが占めています。この2つのWebサーバーの対応でHTTP/2の普及が進んだように、QUICの普及の鍵はNginxとApache HTTPDの正式対応次第ではないかと考えています。
今後もウェブ高速化、パフォーマンスの観点からQUICの対応状況を注視していきたいと思います。