【入門編】HPACKにおけるハフマン符号化の適用 – HTTPプロトコル・通信規格実践ガイド

こんにちは!ネットワークの世界へようこそ。インフラやプロトコルの面白さに魅せられて日々パケットを追いかけている、技術メディア主筆ライターです。

皆さんは普段、何気なくスマホやパソコンでウェブサイトを見ているとき、「なんだか最近のウェブサイトは表示が速くなったな」と感じたことはありませんか?その裏側を支えている主役の一つが「HTTP/2」という通信規格です。

HTTP/2には、1本の通信路で同時にいくつものデータをやり取りする「マルチプレクシング」をはじめ、通信を高速化するための様々な工夫が詰まっています。その中でも今回は、通信の荷物をギュッと小さくパッキングする技術「HPACK(エイチパック)におけるハフマン符号化」にスポットを当てていきたいと思います。

「ハフマン符号化……? なんだか数学のテストみたいで難しそうだな」と思いましたか?
大丈夫です! 小難しいパケットの構造やビットの計算式はいったん脇に置いて、身近な例えを交えながら一歩ずつ優しく紐解いていきますので、どうぞリラックスしてついてきてくださいね。

—

1. なぜ、ウェブの「ヘッダー」を小さくする必要があるの?

私たちがブラウザでウェブページを開くとき、裏側では「このページをください」「はい、どうぞ」というリクエストとレスポンスのやり取りが行われています。このとき、本体のデータ(画像やテキスト)だけでなく、「HTTPヘッダー」というお供のメタデータが一緒に送信されています。

このHTTPヘッダーには、例えば以下のような情報が書かれています。

  • ブラウザの種類はこれです
  • 受け入れられる言語は日本語です
  • どのサイトのどのページを見に来ましたよ

非常に大切な情報なのですが、ここでちょっとした問題が起きます。
インターネットの世界では、同じようなやり取りが何度も繰り返されますよね。そのため、「毎回、ほぼ同じ意味の長い英語の文字列を、律儀に全部送信している」という無駄が発生していたのです。

「毎回、宛先や差出人の長い住所を全部手書きして郵便を出しているようなもの」と言えば、そのもどかしさが伝わるでしょうか? 「もっと通信の無駄を減らして、パケットを軽くしたい!」というエンジニアたちの執念から生まれたのが、HTTP/2のヘッダー圧縮技術「HPACK」なのです。

—

2. ハフマン符号化ってなに? 郵便配達に例えてみよう

HPACKの心臓部の一つが「ハフマン符号化(Huffman Coding)」というデータ圧縮の仕組みです。名前こそいかにもプログラミングっぽくて身構えてしまいますが、やっていることは非常にシンプルです。

ここで、身近な例え話に置き換えてみましょう。

ある会社で、毎日たくさんの社内封筒をやり取りしているとします。
宛先や部署名として、次のような文字がよく使われています。

  • よく使われる文字:「の」「は」「す」「る」(日本語で頻出)
  • めったに使わない文字:「ヴ」「ヶ」「づ」

このとき、もし「すべての文字を一律で同じ長さのペンキで書かなければならない」というルールがあったらどうでしょう? めったに使わない「ヴ」を書くのも、「の」を書くのも同じ手間がかかります。

では、こう工夫したらどうでしょうか?
「よく使う文字は、短い略号(例えば1文字のスタンプ)で済ませ、めったに使わない文字には少し長いコードを割り当てよう!」

これがハフマン符号化の基本アイディアです。
「出現頻度が高い文字には短いビット(2進数の0と1)を割り当て、出現頻度が低い文字には長いビットを割り当てる」ことで、テキスト全体のデータ量を物理的にグッと縮めることができるのです。

—

3. HPACKのハフマン符号化がやっていること

HTTPの世界でも同じことが起きています。ウェブのヘッダー名や値(例えば `content-type` や `user-agent` など)には、よく使われるアルファベット(`e`, `a`, `t` など)と、あまり使われない文字(`z`, `q`, `x` など)があります。

HPACKの仕様書(RFC 7540 / RFC 7541)のなかには、あらかじめ世界中のウェブトラフィックを分析して作られた「ハフマン符号表(Huffman Table)」という辞書が用意されています。

ざっくり言うと、次のようなイメージです。

| 文字 | 一般的な文字コード (1文字=8ビット) | ハフマン符号化後のコード (一例) |
| :— | :— | :— |
| e (よく出る) | 01100101 (8ビット) | `1110` (4ビット) とか短くなる! |
| z (めったに出ない)| 01111010 (8ビット) | `1111111101` (10ビット) と長くなる! |

「あれ? めったに出ない文字は逆に長くなっているじゃないか!」と気づいた方は鋭いですね。その通りです。
しかし、文章全体で見れば、「圧倒的に多く登場する短い文字」の恩恵が、「たまに出る長い文字」のペナルティを遥かに上回るため、トータルでのデータサイズを劇的に小さくできるという魔法のような仕組みになっています。

—

4. 実務の現場ではどう見えている?(パケットの挙動を覗き見)

インフラエンジニアやプロトコルスペシャリストとして現場に立っていると、ブラウザの「開発者ツール(DevTools)」や、パケットキャプチャツール(Wiresharkなど)を使って、この通信の様子を覗き見する機会がたくさんあります。

例えば、Google ChromeなどのDevToolsを開き、「ネットワーク」タブの「プロトコル」列を表示させてみてください。`h2`(HTTP/2)という表示が見つかるはずです。

HTTP/2の通信において、ヘッダーはバイナリ(0と1の塊)に変換され、さらにハフマン符号化によってパッキングされて流れていきます。実務でNode.jsやGoなどの言語を使ってHTTP/2サーバーを実装・デバッグする際も、この圧縮・展開の処理はライブラリやランタイムが裏側で自動的にやってくれます。

// 【参考】Node.jsでHTTP/2サーバーを構築する際のイメージコード
const http2 = require(‘http2’);
const fs = require(‘fs’);

// 秘密鍵と証明書を読み込んで、HTTP/2(安全な通信)のサーバーを立ち上げる
const server = http2.createSecureServer({
key: fs.readFileSync(‘localhost-privkey.pem’),
cert: fs.readFileSync(‘localhost-cert.pem’)
});

server.on(‘stream’, (stream, headers) => {
// ブラウザから送られてきたヘッダーは、HPACKによって自動的にデコード(復元)されている!
console.log(‘受け取ったヘッダー:’, headers[‘:path’]);

// レスポンスを返す(HTTP/2のマルチプレクシングとヘッダー圧縮の恩恵を受ける)
stream.respond({
‘content-type’: ‘text/html; charset=utf-8’,
‘:status’: 200
});
stream.end(‘

HTTP/2の世界へようこそ!

‘);
});

server.listen(8443, () => {
console.log(‘HTTP/2サーバーがポート8443で起動しました’);
});

私たちが普段書くコードの中では意識しなくても、このコードが動く裏側で、HPACKとハフマン符号化がパケットをスリムにし、ミリ秒単位の高速化に貢献してくれているのです。

—

5. おわりに:通信の裏側にある「粋な工夫」を楽しもう

今回は、HTTP/2のHPACKにおける「ハフマン符号化」について、郵便の例えや身近な仕組みを交えて解説してきました。

  • ヘッダーの無駄な重複送信を防ぐために「HPACK」がある。
  • その中で、よく使う文字を短く、使わない文字を長く表現して全体を縮めるのが「ハフマン符号化」。
  • 私たちが意識しなくても、ブラウザやサーバーの裏側でパケットが軽やかにパッキングされている。

ネットワークやプロトコルの世界は、一見すると無機質なコードの羅列に見えますが、その背景には「どうすればもっと速く、快適に情報を届けられるか」という先人たちの知恵や工夫、いわば「エンジニアたちの粋な計らい」がたくさん詰まっています。

この記事をきっかけに、日頃何気なく使っているウェブの通信規格やパケットの挙動に、少しでも興味を持っていただけたら最高に嬉しいです。

それでは、また次回の技術解説でお会いしましょう! パケットと共にあらんことを。

コメント

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