APIが処理するすべてのHTTPリクエストは、ほとんどの開発者が意識しないトランスポート層の上に成り立っています。25年間、その答えはTCPでした。しかし、GoogleはTCPの改善を待つことにうんざりし、UDPの上にQUICプロトコルを構築し、IETFがそれを標準化しました。HTTP/3は、そのQUIC上で動作するように構築されたHTTPのバージョンです。
それは配管のように聞こえます。実際、その通りです。しかし、この配管は、APIの接続速度、不安定なモバイルネットワークでの動作、並列リクエストがどのように接続を共有するかに影響を与えます。APIを設計または運用するなら、何が変わり、何が変わらなかったのか、そして自身のエンドポイントが現在何に対応しているのかを知っておくべきです。
これらのすべてにおいて、一つだけ変わらないことがあります。それは、HTTP/1.1、HTTP/2、HTTP/3のいずれにおいても、リクエスト、レスポンス、ステータスコード、JSONペイロードは同じに見えるという点です。ApidogのようなツールはAPI層でテストおよびデバッグを行うため、インフラストラクチャがどのトランスポートバージョンをネゴシエートしていても、エンドポイントの動作について検証したことはすべて真実であり続けます。すでにHTTP/2とは何か、そしてHTTP/2 APIをテストする方法に関する当社の解説を読んでいるなら、この記事はその続きとなります。
QUICプロトコルとは何か?
QUICはRFC 9000で標準化されたトランスポートプロトコルです。TCPの代わりにUDP上で動作し、TCPが提供する機能(信頼性、順序付け、輻輳制御)をユーザー空間でストリームごとに再構築し、最初のパケットから暗号化が組み込まれています。
それを定義する4つの設計上の決定事項は次のとおりです。
UDP上で動作します。TCPはオペレーティングシステムカーネルやインターネット上のミドルボックスに実装されており、進化させることが非常に困難です。UDPは配信保証のない薄いエンベロープであるため、QUICはその上に独自の信頼性レイヤーを構築し、OSのアップグレードではなくライブラリの更新として改善を提供できます。
TLS 1.3が組み込まれており、後付けではありません。TCPの場合、TCPハンドシェイクを完了し、その上に別途TLSハンドシェイクを行います。QUICはこれらを統合します。暗号化の設定はトランスポートハンドシェイク自体の中で行われるため、1回のラウンドトリップで新しい安全な接続が準備できます。暗号化されていないQUICというものは存在しません。
ストリームは独立しています。QUIC接続は多数のストリームを運び、それぞれが独立して配信されます。パケットが失われても、それが属するストリームのみが停止します。これは、後ほど説明するTCPのヘッドオブラインブロッキングに対する解決策です。
接続はネットワークの変更後も維持されます。TCPはIPアドレスとポートで接続を識別します。どちらかを変更すると(Wi-Fi範囲外に出る、5Gに切り替えるなど)、接続は切断されます。QUICは代わりに接続IDで接続を識別するため、クライアントは新しいネットワークに移動しても同じ論理接続を維持できます。再接続や新たなハンドシェイクは不要です。
RFC 9114で定義されているHTTP/3は、HTTPのセマンティクスをQUICストリームにマッピングしたものです。メソッド、ヘッダー、ステータスコードは同じです。ワイヤーフォーマットとトランスポートが異なります。
HTTP/3 vs HTTP/2: 実際には何が変わったのか
HTTP/2はHTTP/1.1からの大きな進歩でした。多重化(multiplexing)を導入したため、多数のリクエストがキューイングされたり6つの並列ソケットを開いたりする代わりに、1つのTCP接続を共有できるようになりました。しかし、その下にはTCPが残っており、HTTP/2単独では解決できない問題を生み出しました。
TCPは単一のバイトストリームの順序付き配信を保証します。1つのパケットが欠落すると、TCPは再送信が届くまで、その後のすべてのバイト(まったく関係のないHTTP/2ストリームに属するバイトであっても)を保留します。1つの失われたパケットが、接続上で多重化されている20すべてのリクエストを停止させてしまいます。これがトランスポート層のヘッドオブラインブロッキングであり、損失の多いネットワークでは、複数の接続を持つHTTP/1.1よりもHTTP/2が遅くなる可能性があります。
HTTP/3は共有バイトストリームを排除します。各リクエストは独自の配信順序を持つ独自のQUICストリームにマッピングされます。ストリーム5を運ぶパケットが失われても、ストリーム6から24は流れ続けます。これにより、HTTP/2の図が常に主張していた多重化が、ついにその通りに機能するようになります。
ハンドシェイクの計算も変わりました。
| TCP+TLS 1.3上のHTTP/2 | QUIC上のHTTP/3 | |
|---|---|---|
| 新規接続設定 | 2ラウンドトリップ (TCP + TLS) | 1ラウンドトリップ |
| 再開された接続 | 1ラウンドトリップ | 0ラウンドトリップ (0-RTT) |
| パケット損失の影響 | 全てのストリームをブロック | 1つのストリームをブロック |
| ネットワーク切り替え (Wi-Fiから5G) | 接続が切断され、完全に再接続 | 接続が移行し、維持される |
| 暗号化 | 理論上はオプション、独立したレイヤー | 必須、TLS 1.3が統合されている |
0-RTTの行には注意が必要です。クライアントが以前に接続したことのあるサーバーに再接続する際、QUICはハンドシェイクが完了する前に最初のパケットでアプリケーションデータを送信することを許可します。これはレイテンシにとって素晴らしいことです。しかし、0-RTTデータは攻撃者によって傍受され、リプレイされる可能性があります。そのため、サーバーは0-RTTでは冪等なリクエストのみを受け入れる必要があります。リプレイされたGETは無害ですが、クレジットカードに課金するリプレイされたPOSTはそうではありません。エッジで0-RTTを有効にする場合は、非冪等なAPI呼び出しが除外されていることを確認するか、CDNがこれを行っていることを確認してください。
APIにとってHTTP/3が意味すること
プロトコルのアップグレードは、測定可能な何らかの変化をもたらす場合にのみ意味があります。HTTP/3がAPIトラフィックに影響を与える点と、そうでない点を見ていきましょう。
接続設定がより安価になる
RTTが60msの一般的なモバイルクライアントは、最初のAPIリクエストがデバイスから送信される前に、TCP+TLSのセットアップに約120msを費やします。HTTP/3はこれを約60msに短縮し、再開時にはほぼゼロになります。頻繁に新しい接続を開く(コールドスタート、バックグラウンドでの起動、短命なセッションなど)モバイルアプリから呼び出されるAPIの場合、これらの最初のリクエストごとに節約効果が得られます。ウォームな接続プールを保持するサーバー間統合では、ハンドシェイクは償却されて無関係になり、何も気づかないでしょう。
モバイルクライアントは接続切断を停止する
接続移行はAPIチームにとって隠れた目玉機能です。ユーザーがオフィスWi-Fiでリクエストを開始し、エレベーターに向かうと、電話はセルラーネットワークに切り替わります。TCPの場合、その進行中のリクエストは失敗し、クライアント側の再試行ロジック(再試行ロジックはありますよね?)が完全な再接続とともに起動します。QUICの場合、接続はデバイスに追従して新しいネットワークに移行します。クライアントログのタイムアウトエラーが減り、中途半端な書き込みについて考える必要が少なくなります。
障害モードのない多重化
REST APIの場合、HOLブロッキングの修正は、クライアントが多くのリクエストを並行して実行する場合に最も重要になります。例えば、15個のウィジェットを更新するダッシュボードや、一括更新をプッシュする同期エンジンなどです。クリーンなネットワークでは、HTTP/2とHTTP/3のパフォーマンスはほぼ同じです。しかし、1~2%のパケット損失(混雑した会議のWi-Fi、地下鉄のセルラーなど)が加わると、HTTP/3は並列リクエストを独立して処理し続けるのに対し、HTTP/2はそれらを一斉に停止させてしまいます。
gRPCは今のところHTTP/2に留まる
gRPCは設計上HTTP/2に結びついており、そのワイヤーコントラクトはHTTP/2のフレーミングとトレーラーに依存しています。gRPCエコシステムはHTTP/3マッピングを標準化しておらず、主要な実装(Go、Java、Python、Node)にはそれが含まれていません。.NETのKestrelサーバーは実験的な機能としてHTTP/3経由でgRPCを提供できますが、これは例外と考えるべきです。もしあなたのアーキテクチャが内部APIパフォーマンスのためにgRPCとHTTP/2に依存しているなら、今年のHTTP/3への移行を計画する必要はありません。
ストリーミングとリアルタイムトラフィック
Server-Sent Eventsは通常の長寿命HTTPレスポンスであるため、HTTP/3上でも変更なく動作します。WebSocketsはより複雑です。WebSocketのアップグレードはTCP向けに設計されており、そのHTTP/3相当(RFC 9220、および登場しつつあるWebTransport API)はまだサポートがまばらです。リアルタイム機能のためにWebSocketsとプレーンなHTTPを比較検討している場合、HTTP/3の可用性はまだ決定を左右する要因となるべきではありません。
正直な部分:HTTP/3が役に立たない場合
ほとんどのAPIレイテンシ問題は、トランスポートプロトコルとは関係ありません。もしインデックスされていないデータベースクエリのせいでエンドポイントが400msかかる場合、HTTP/3はその遅いレスポンスを60ms早く配信するでしょう。キャッシュ、ペイロード設計、N+1クエリ、接続再利用が実際のAPIパフォーマンスを支配しており、トランスポートについて考える前にこれらを徹底すべきです。構造化されたAPIパフォーマンステストは、通常、プロトコルアップグレードよりも10倍大きな改善点を見つけ出すでしょう。
HTTP/3は特定の条件下でその真価を発揮します。
- ラウンドトリップの節約が固定的な割合で利益をもたらす、高レイテンシのリンク
- HOLブロッキングの解消が複合的に効果を発揮する、損失の多いネットワーク
- セッション途中でネットワークを切り替えるモバイルクライアント
- 少ない長期接続よりも、多くの短期接続
信頼性の高いネットワークを介して同じリージョンのサーバーによって利用される典型的なJSON APIの場合、その違いはベンチマークでは測定可能ですが、ユーザーには見えません。その他に2つの実用的な注意点があります。一部の企業ネットワークではUDPポート443がブロックされています(クライアントは自動的にHTTP/2にフォールバックするため、何も壊れません)、そしてQUICのユーザー空間での暗号化は、調整されたカーネルTCPよりも接続あたりのサーバーCPUコストが現在高くなります。
現在のサポート状況:今日、誰がHTTP/3を利用しているか
導入は、ほとんどのバックエンド開発者が想定しているよりも進んでいます。
- ブラウザ: Chrome、Edge、Firefox、Safariはすべて、HTTP/3がデフォルトで有効になっています。
- CDNおよびエッジ: Cloudflare、Fastly、Akamai、CloudFrontがサポートしています。Cloudflareではトグルで切り替えます。ほとんどのチームにとって、これが実用的な方法です。エッジでHTTP/3を終端し、エッジからオリジンへはHTTP/1.1またはHTTP/2を使用します。
- サーバー: Nginxはバージョン1.25で
listen 443 quic;により実験的なHTTP/3を追加しました。Caddyはデフォルトで有効です。LiteSpeedとHAProxyはサポートしています。Apache httpdはサポートしていません。 - ランタイム: Node.jsには安定した組み込みのHTTP/3サーバーサポートがありません。これが、エッジ終端が一般的なデプロイメントであるもう一つの理由です。
- curl: HTTP/3対応のTLSスタックに対してビルドされている場合、
--http3フラグでサポートされます。どのビルドに含まれるかについては、curl HTTP/3ドキュメントを参照してください。
APIがHTTP/3に対応しているかを確認する方法
検出はAlt-Svcレスポンスヘッダーを通じて行われます。HTTP/3を宣伝するサーバーは、最初の(HTTP/2)リクエストに対して次のような応答を返します。
alt-svc: h3=":443"; ma=86400
これはクライアントに対し、この同じサービスが今後24時間、UDPポート443経由でHTTP/3で利用可能であることを伝えます。curlで確認するには次の通りです。
curl -sI https://www.cloudflare.com | grep -i alt-svc
# alt-svc: h3=":443"; ma=86400
HTTP/3経由で直接リクエストを行うには(HTTP/3対応のcurlビルドが必要):
curl --http3 -I https://cloudflare-quic.com
# HTTP/3 200
ステータスラインにはHTTP/2ではなくHTTP/3と表示されます。Chrome DevToolsでは、Networkタブを開き、列ヘッダーを右クリックしてProtocol列を有効にし、API呼び出しの横にh3があるか確認します。本番環境では、ネゴシエートされたプロトコルをアクセスログに追加してください。h2とh3のトラフィックの割合は、どれだけのクライアントがその恩恵を受けているかを示します。
トランスポートを検証する一方で、動作も検証しましょう。Apidogを同じエンドポイントに向けて、ステータスコード、レスポンススキーマ、レイテンシ予算をアサートしてください。基盤となるAPIコントラクトが壊れていれば、トランスポートレベルでの改善も無意味であり、プロトコル変更では救えないのがコントラクトチェックの層です。Apidogを無料でダウンロードし、エッジでHTTP/3を有効にする前と後で同じテストスイートを実行してください。モバイルネットワークでの応答時間の差が、ベンチマークの見出しではなく、あなたの実際の答えとなるでしょう。
よくある質問
HTTP/3はHTTP/2より高速か?
クリーンで低レイテンシのネットワークでは、ほとんど差はありません。損失の多い、または高レイテンシのネットワークでは、はい、多くの場合顕著に高速です。なぜならHTTP/3はハンドシェイクのラウンドトリップを削減し、1つのパケット損失によって多重化されたすべてのリクエストが停止することがなくなるためです。効果を主張する前に、自身のトラフィックプロファイルで測定してください。そして、HTTP/2も依然として優れていることを忘れないでください。もしそこで接続エラーが発生する場合、それは通常、プロトコルの制限というよりも、SSLV3_ALERT_HANDSHAKE_FAILURE問題のようなTLS層の問題であることが多いです。
HTTP/3はTCPを使用するか?
いいえ。HTTP/3はQUIC上で動作し、QUICはUDP上で、通常はポート443を使用します。QUICはTCPが提供していた信頼性、順序付け、輻輳制御を、ストリームごと、かつユーザー空間で再実装しています。ネットワークでUDP 443がブロックされている場合、クライアントは自動的にTCP上のHTTP/2にフォールバックします。
HTTP/3のためにAPIコードを変更する必要があるか?
ほとんどありません。HTTPのセマンティクスは変更されていません。メソッド、ヘッダー、ステータスコード、ボディは同じです。作業はインフラストラクチャ(CDN、ロードバランサー、またはサーバーでの有効化)と、1つの設計確認にあります。0-RTTの早期データが冪等なリクエストに限定されていることを確認してください。
HTTP/3経由でgRPCを使用できるか?
今のところ、ほとんどできません。gRPCのワイヤーフォーマットはHTTP/2に結びついており、主流のgRPCライブラリはHTTP/3トランスポートを提供していません。.NETは実験的なサポートを持っています。gRPCサービスはHTTP/2に維持し、まず効果が期待できる場所、すなわち公開されているブラウザ向けおよびモバイル向けのRESTエンドポイントでHTTP/3を採用しましょう。
