02. 土台: QUIC と WebTransport

🎯 この章のゴール

  • MoQ が TCP ではなく QUIC を選んだ理由(HoL ブロッキング・ストリーム・データグラム)を説明できる
  • ネイティブ QUIC と WebTransport の 2 つの接続方法を区別できる
  • moqt:// URI と ALPN によるバージョン交渉を知る

💡 ひとことで言うと

QUIC は、1 本の接続の中に独立したレーンを何本でも引ける道路です。TCP では 1 台の事故(パケットロス)で全レーンが渋滞しますが、QUIC では渋滞がそのレーンだけで済みます。

TCP の悩み: Head-of-Line ブロッキング

TCP は「順序どおりに届く 1 本のバイト列」です。途中のパケットが 1 つ失われると、再送が届くまで、後ろのデータは届いていてもアプリに渡せません。これを HoL(Head-of-Line)ブロッキングと呼びます。

ライブ映像では、古いフレームの再送を待つ間に新しいフレームまで止まってしまいます。

TCP(1 本のバイト列)G1G2 ロスG3 待ちG4 待ち← G2 の再送まで全部止まるQUIC(ストリームごとに独立)G1stream 2G2 ロスstream 6(ここだけ待つ)G3stream 10G4stream 14(届き続ける)
TCP ではロスが全体を止め、QUIC ではそのストリームだけが待つ

QUIC が MoQ にくれるもの

QUIC の機能MoQ での使い方
ストリーム(多数・独立・安価)Group / Subgroup ごとに 1 本のストリームを使い、ロスの影響を局所化する
ストリームのリセット古くなったデータの送信・再送を途中で打ち切る(部分的な信頼性)
ストリームの優先度制御輻輳時に「新しい」「重要な」データを先に送る(09 章)
DATAGRAM 拡張(RFC 9221)再送しない小さな Object を送る
TLS 1.3 内蔵・0-RTT暗号化必須。再接続なら最初のパケットからリクエストを送れる
コネクションマイグレーションWi-Fi ↔ モバイル回線の切り替えでも接続を維持

MOQT を QUIC 直接、または WebTransport over HTTP/3 で動かす場合、QUIC の DATAGRAM 拡張のサポートとネゴシエーションが MUST です。

2 つの接続方法

MOQT は「ストリームとデータグラムを持つトランスポート」の上なら同じように動きます。draft-22 では次の 2 つが定義されています。

1. ネイティブ QUIC

サーバーやネイティブアプリ向け。QUIC 接続を直接張り、TLS の ALPN で MOQT を選びます。URI の authority や path は、MOQT の最初のメッセージ SETUP の中の Setup Option(AUTHORITY / PATH)で伝えます。

2. WebTransport

ブラウザ向け。WebTransport は「HTTP/3 の上で QUIC のストリームとデータグラムを Web ページに開放する」仕組みです。クライアントは moqt URI のスキームを https に置き換え、その URL に extended CONNECT を送ってセッションを開きます。MOQT のバージョンは WT-Available-Protocols ヘッダーで交渉します。

WebTransport は HTTP/2(TCP)の上でも動きますが、その場合は TCP の HoL ブロッキングが戻ってくるので、MOQT は動くものの遅延特性は大きく異なります。

moqt://relay.example.com/live?token=abc
  │       │                │     └─ query(スコープには含まれない)
  │       │                └─ path-abempty
  │       └─ authority(省略時はポート 443)
  └─ scheme
WebTransport の場合 → https://relay.example.com/live?token=abc へ CONNECT

MOQT URI とスコープ

MOQT サーバーは moqt スキームの URI で識別されます。

moqt-URI = "moqt" "://" authority path-abempty [ "?" query ]
  • authority と path が同じなら同じスコープ(トラック名が一意な範囲、03 章)とみなします。query は含みません
  • フラグメント(#type:value)はサーバーに送られず、セッション確立後にクライアント側で解釈されます

ALPN によるバージョン交渉

ドラフトの版ごとに互換性がないため、ALPN でバージョンを決めます。

版ALPN
最終版(RFC)moqt
draft-N(-15 以降)moqt-N(例: draft-22 → moqt-22)
-14 以前すべて moq-00。SETUP メッセージの中で版を交渉

クライアントは対応する MOQT の ALPN と h3 を TLS ClientHello に並べて提示できます。サーバーが MOQT の ALPN を選べばネイティブ QUIC、h3 を選べば WebTransport で続行します。

sequenceDiagram
  participant C as クライアント
  participant S as サーバー
  C->>S: ClientHello (ALPN: moqt-22, moqt-21, h3)
  alt MOQT の ALPN を選択
    S-->>C: ServerHello (ALPN: moqt-22)
    Note over C,S: ネイティブ QUIC で MOQT セッション
  else h3 を選択
    S-->>C: ServerHello (ALPN: h3)
    C->>S: extended CONNECT https://… (WT-Available-Protocols)
    Note over C,S: WebTransport 上で MOQT セッション
  end

🧪 考えてみよう

ブラウザの JavaScript からはネイティブ QUIC のソケットを直接開けないので、ブラウザは WebTransport を使います。では、WebTransport がまだ安定して使えないブラウザではどうするのでしょう? moq.dev の実装は WebSocket へのフォールバックを用意しています。その場合、TCP の HoL ブロッキングは避けられません。

📝 まとめ

  • TCP は 1 本のバイト列なので、ロスが全データを止める(HoL ブロッキング)
  • QUIC のストリーム・リセット・優先度・データグラムが MoQ の低遅延を支える
  • 接続方法はネイティブ QUIC(ALPN moqt-N)と WebTransport(https URL に CONNECT)の 2 つ

参考

✅ 理解度クイズ

Q1
TCP 上で複数の映像フレームを送るとき、1 つのパケットが失われると何が起きる?
Q2
MOQT を QUIC 直接、または WebTransport over HTTP/3 で動かす場合に必須とされている QUIC の拡張は?
Q3
moqt://relay.example.com/live に WebTransport で接続するとき、クライアントは何をする?
Q4
draft-22 を実装したエンドポイント同士が QUIC で使う ALPN 値は?