【実務・中級編】HPACKヘッダー圧縮の基本アルゴリズム – HTTPプロトコル・通信規格実践ガイド

HTTP/2 HPACKの深淵:なぜあなたのAPIは「ヘッダー」だけで肥大化するのか

ネットワークエンジニアとして現場に立っていると、APIのパフォーマンスチューニングで「ペイロードのJSONは削ったのに、なぜかレスポンスが遅い」という相談をよく受けます。その犯人の多くは、肥大化したHTTPヘッダーです。

HTTP/1.1の時代、僕らはCookieやUser-Agent、複雑なAuthorizationヘッダーを毎回律儀に送り続けていました。しかし、HTTP/2の登場により、この「無駄な繰り返し」に終止符が打たれました。それが今回解説するHPACKです。

—

1. HPACKの「賢さ」の正体:テーブルという名の記憶

HPACKの本質は、一言で言えば「一度送ったヘッダーは二度と送らない」という文脈の共有にあります。これを実現するために、HPACKは二つのテーブルを使い分けます。

静的テーブル (Static Table)

RFC 7541で定義された、世界共通の「辞書」です。たとえば、`method: GET` はインデックス `2`、`path: /` はインデックス `1` と決まっています。クライアントもサーバーも、最初から「これを知っている」という前提で通信を始めます。

動的テーブル (Dynamic Table)

これがHPACKの真骨頂です。通信中に一度送られたヘッダーを、双方のメモリ上に動的に保存します。

  • 1回目:フルネーム(`user-agent: Mozilla/5.0…`)で送る。
  • 2回目以降:インデックス番号(例:`62`)だけで送る。

これだけで、ヘッダーサイズは劇的に圧縮されます。数KBあったリクエストヘッダーが、数バイトになることも珍しくありません。

—

2. 実務で遭遇する「ハフマン符号化」の役割

テーブルに載らないヘッダー名や値はどうなるのか?そこで登場するのがハフマン符号化です。

これは「出現頻度の高い文字には短いビット列を、低い文字には長いビット列を割り当てる」という古典的かつ強力な圧縮手法です。HPACKでは、ヘッダーの各文字をこのアルゴリズムで圧縮してから送信します。もし皆さんが `tcpdump` や `Wireshark` で通信を覗いたとき、ヘッダー部分が意味不明なバイナリの羅列に見えたら、それはハフマン符号化が正しく機能している証拠です。

—

3. 実践:curlでパケットの挙動を追う

百聞は一見に如かず。実際に `curl` を使って、この圧縮がどう動いているかを可視化してみましょう。デバッグ時には `-v` だけでなく、フレームレベルで確認できる `–http2` との詳細ログが役立ちます。

HTTP/2でリクエストを送り、通信の全貌を記録する
-v: 冗長表示
–http2: 強制的にHTTP/2を使用
curl -v –http2 https://api.example.com/v1/resource \
-H “Authorization: Bearer my-secret-token” \
-H “X-Custom-Header: my-value”

この際、サーバー側(Nginxなど)のログで `http2_max_field_size` や `http2_header_table_size` を調整しておくと、動的テーブルの効率を最適化できます。

Nginx設定のヒント:

http {
# デフォルトは4KB。APIヘッダーが巨大な場合はメモリと相談して調整
http2_header_table_size 4k;

# ハフマン符号化はデフォルトで有効ですが、CPU負荷が高い場合は状況に応じて
# ただし、現代のCPUなら気にする必要はほぼありません
}

—

4. エンジニアが知っておくべき「落とし穴」

HPACKは魔法ではありません。注意すべき点がいくつかあります。

1. 動的テーブルのサイズ制限: メモリを無限に食うわけにはいかないため、上限があります。上限を超えると古いエントリから破棄されます。ヘッダーを頻繁に変えるような設計だと、テーブルが常に追い出され、圧縮効率が落ちる「スラッシング」が発生します。
2. セキュリティ (CRIME攻撃対策): 圧縮されたデータに秘密情報が含まれていると、サイドチャネル攻撃を受けるリスクがあります。特にCookieに機密情報を含める際は、ヘッダー圧縮の特性を考慮した設計が必要です。
3. デバッグの難易度: WiresharkでHTTP/2のヘッダーを読む際、HPACKのコンテキスト(以前の通信の履歴)がないと、パケットを個別に切り出しても中身が読めません。「なぜかWiresharkでヘッダーが復元できない!」というときは、ストリームの最初からキャプチャを開始していないケースが大半です。

—

最後に:なぜ今、これを理解すべきなのか

Web API設計がマイクロサービス化する中で、サービス間通信(gRPCなど)の多くはHTTP/2(およびHPACKの進化版であるQPACK)の上で動いています。

「なんとなく速い」で済ませるのではなく、「どのヘッダーを動的テーブルに残すべきか」を意識したリクエスト設計ができるエンジニアこそが、高負荷環境でも揺るがないインフラを構築できると僕は信じています。

皆さんの設計するAPIが、明日から少しでも軽快に、そして効率的にパケットを飛ばせるようになることを願っています。質問があればいつでもどうぞ。ネットワークは嘘をつきませんから。

コメント

タイトルとURLをコピーしました