TL

HTTP/3 の QPACK:ヘッダ圧縮の動的テーブル設計

なぜHTTP/3はHPACKをそのまま使えなかったのか。QPACKが順序非依存のストリームでヘッダを圧縮し、HoLブロッキングを避けつつ圧縮率を保つ設計を内部から理解できます。

応用QPACKHTTP/3QUICヘッダ圧縮HPACK最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.HPACK は動的テーブルの更新順序に依存するため、QUIC のストリーム独立配送と相性が悪く、HTTP/3 では QPACK が代替する。
  • 2.QPACK は専用のエンコーダストリームでテーブルを更新し、各ヘッダブロックは必要なテーブル状態を Required Insert Count で明示することで参照の整合を取る。
  • 3.未挿入のエントリを参照するヘッダブロックはデコーダ側でブロックされる。Blocked Streams 上限と「動的参照を使わない」選択で詰まりを制御できる。

なぜ HPACK をそのまま使えないのか

HTTP/2 のヘッダ圧縮 HPACK は、過去に送ったヘッダを動的テーブルに蓄え、次回以降は番号参照で送ることで冗長な文字列の再送を避けます。問題はその一貫性モデルです。HPACK のテーブル更新はヘッダブロックを処理したそのままの順序で進む前提で、エンコーダとデコーダのテーブルは「同じ系列を同じ順で適用する」ことで同期します。

HTTP/2 は単一の TCP コネクション上で全フレームが厳密な順序で届くためこれが成立しました。しかし HTTP/3 の土台である /network/quic-internals/ の QUIC は、ストリームごとに独立して順序保証する代わりにストリーム間の到着順は保証しません。あるストリームのヘッダが先に到着し、それが参照するテーブル更新を載せた別ストリームがまだ届いていない、という状況が起こり得ます。HPACK をそのまま載せると、テーブルの状態が要求に追いつかず復号できないか、あるいは順序を保つために TCP 同様の Head-of-Line(HoL)ブロッキングを再導入してしまいます。QPACK(RFC 9204)はこの矛盾を解くための再設計です。

3 つのストリームに役割を分ける

QPACK はテーブル更新と参照を別の経路に分離します。

  • エンコーダストリーム: 単方向ストリーム。動的テーブルへの挿入命令だけを流す。順序保証されたストリームなので、デコーダはこの命令列を送られた順に適用してテーブルを構築する。
  • デコーダストリーム: 単方向ストリーム。デコーダからエンコーダへ確認応答を返す(後述の Section Acknowledgement など)。これによりエンコーダは「どこまで相手が処理したか」を知る。
  • リクエスト/レスポンスストリーム: 実際の HTTP メッセージが流れる双方向ストリーム。各メッセージのヘッダはヘッダブロック(エンコード済みフィールドセクション)として載る。
クライアント                          サーバー
  エンコーダストリーム ──挿入命令──▶  デコーダの動的テーブルを更新
  リクエストストリーム ──ヘッダブロック──▶  テーブルを参照して復号
  デコーダストリーム  ◀──確認応答──     どこまで処理したかを通知

要点は、テーブルを書き換える命令(エンコーダストリーム)と、それを参照するヘッダ(リクエストストリーム)が別のストリームに分かれていることです。ヘッダブロック自身はテーブルを変更しません(厳密にはリテラルや参照のみで、挿入は伴わない使い方を基本とする)。これにより、ヘッダブロックの処理が他ストリームの順序に巻き込まれにくくなります。

テーブルの整合をどう取るか:Required Insert Count

ストリーム間順序が無いと、ヘッダブロックが参照する動的エントリがまだ挿入されていない、という不整合が起こります。QPACK はこれを参照の前提条件を明示することで扱います。各ヘッダブロックは先頭に Required Insert Count(RIC) を持ち、「このブロックを復号するには動的テーブルに最低この個数の挿入が済んでいる必要がある」と宣言します。

  • デコーダは自分のテーブルの挿入数(Insert Count)が RIC 以上なら即座に復号できる。
  • まだ満たない(エンコーダストリームの挿入命令が遅れている)なら、そのストリームをブロックし、条件が満たされるまで待つ。

つまり HoL ブロッキングを「接続全体」から「動的参照を持つ個別ストリーム」へ局所化したのが QPACK の核心です。動的テーブルを一切参照しないヘッダブロック(RIC が 0)は、テーブル状態に関係なく常に即復号できます。

相対インデックスと Base

動的テーブルのインデックスは挿入が進むほど絶対位置がずれるため、ヘッダブロック内では Base を基準にした相対参照で表します。RIC と Base の符号化に固定の基準(既知の挿入数)を使うことで、エンコーダとデコーダが同じエントリを指していることを順序非依存に保証します。

ブロッキングをどこまで許すか

エンコーダは「相手をブロックさせ得るストリーム」の数を Blocked Streams の上限(SETTINGS_QPACK_BLOCKED_STREAMS)以内に収めねばなりません。デコーダがこの値を通知し、エンコーダは未確認の挿入を参照するヘッダブロックの本数がそれを超えないよう動的参照を自制します。上限を 0 にすれば一切ブロックは起きませんが、その場合エンコーダは確認済みのエントリしか参照できず、圧縮率は下がります。

エンコーダとデコーダの同期はデコーダストリームの確認応答で進みます。

  • Section Acknowledgement: あるストリームのヘッダセクションを復号し終えた通知。これによりエンコーダは、そのブロックが参照したエントリは相手に届いたと確信できる。
  • Insert Count Increment: 挿入命令を処理してテーブルが進んだ通知。エンコーダの未確認窓を前進させる。
  • Stream Cancellation: リセットされたストリームの参照が解放された通知。
観点HPACK (HTTP/2)QPACK (HTTP/3)
前提とする配送全フレームが厳密順序ストリーム独立・順序非保証
テーブル更新の経路ヘッダブロックと同一ストリーム専用エンコーダストリームに分離
参照前提の表明暗黙(順序で同期)Required Insert Count で明示
HoL の影響範囲更新順序に依存(QUIC上では破綻)動的参照を持つ個別ストリームに局所化
ブロック量の制御なしBlocked Streams 上限で調整可能

圧縮率とブロッキングのトレードオフ

エンコーダ実装には設計上の選択肢があります。動的テーブルを積極的に使えば圧縮率は上がりますが、まだ確認されていない挿入を参照すると相手をブロックさせる危険が増します。逆に静的テーブル(よく使うヘッダの固定 99 エントリ)とリテラルだけに頼れば、ブロックは皆無でも圧縮効率は落ちます。

実務的なエンコーダは、Section Acknowledgement で確認済みの範囲を主に参照し、Blocked Streams の余裕の範囲でのみ未確認エントリを攻めます。動かないヘッダ(:method や定番の accept-encoding など)は静的テーブルで賄い、Cookie のように長く繰り返すヘッダこそ動的テーブルに載せる、という使い分けが効きます。

Huffman 符号化は HPACK と共通だが別問題

QPACK の文字列リテラルは HPACK と同じ静的 Huffman 表で符号化できますが、Huffman はあくまで個々の文字列を縮める層であり、HoL 回避とは独立した話です。QPACK が解決したのは「テーブルの一貫性をストリーム順序に縛られず保つ」ことであって、文字列圧縮の方式そのものは HTTP/2 から大きく変えていません。

試験・面接の要点

「なぜ HTTP/3 は HPACK を使えないか」は、HPACK が更新順序に依存し QUIC のストリーム独立配送で同期が壊れるから。「QPACK の HoL 回避の鍵」はエンコーダ/デコーダストリームへの更新分離と Required Insert Count による参照前提の明示。この 2 点が頻出です。

まとめ

QPACK は、HPACK が暗黙に依存していた「ヘッダと同じ経路でテーブルを順序通り更新する」という前提を捨て、テーブル更新を専用のエンコーダストリームへ追い出し、各ヘッダブロックに Required Insert Count で参照前提を持たせることで、QUIC の順序非依存な配送上でも圧縮を成立させます。ブロッキングは接続全体ではなく動的参照を持つストリームに局所化され、Blocked Streams 上限と確認応答によって圧縮率と詰まりのバランスを実装側が制御できます。HTTP/3 の全体像は /network/http-versions/、土台の鍵交換は /network/tls13-handshake-internals/ と合わせて押さえると、ヘッダ層からトランスポート層までの設計思想が一本につながります。

ネットワーク Article

HTTP/3 の QPACK:ヘッダ圧縮の動的テーブル設計を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

QPACK

比較で見る軸

難易度: advanced / カテゴリ: ネットワーク / タグ数: 5

導入後に効く点

QPACK は専用のエンコーダストリームでテーブルを更新し、各ヘッダブロックは必要なテーブル状態を Required Insert Count で明示することで参照の整合を取る。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
ネットワーク
タグ数
5

判断チェックリスト

  • 自社の用途が「QPACK / HTTP/3」に近いか確認する。
  • 強みである「HPACK は動的テーブルの更新順序に依存するため、QUIC のストリーム独立配送と相性が悪く、HTTP/3 では QPACK が代替する。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

QPACKHTTP/3QUICヘッダ圧縮HPACKQPACKHTTP/3QUIC
参考: 公式情報