Brotli/gzipによるコンテンツ符号化と転送圧縮の原理
テキスト資産を数分の一に縮めて転送を速くする仕組み。Accept-Encoding交渉、DEFLATEとBrotliの辞書・圧縮率・CPUの差、事前圧縮と動的圧縮の使い分けまで原理から理解できる。
- 1.Content-Encodingはブラウザの Accept-Encoding 申告とサーバーの応答ヘッダで圧縮方式を合意し、本文を符号化して転送量を減らす仕組み。
- 2.gzip/DEFLATEはLZ77+ハフマンの汎用圧縮、Brotliは静的辞書とコンテキストモデルで同じ品質域なら高圧縮を出すが、最高品質はCPUコストが重い。
- 3.静的資産はビルド時に最高品質で事前圧縮し、動的応答は中程度の品質でその場圧縮するのが、圧縮率とCPUを両立する定石。
コンテンツ符号化とは何か
HTTPの**コンテンツ符号化(Content-Encoding)**は、応答本文を可逆圧縮して転送し、受信側で展開する仕組みです。HTML・CSS・JavaScript・JSONといったテキストは冗長性が高く、一般に元の20〜30%程度まで縮みます。転送バイト数が減れば、ネットワーク往復で本文を運び切るまでの時間が短くなり、結果としてCore Web VitalsのLCPやFCPが改善します。
ここで区別すべきは、コンテンツ符号化と**転送符号化(Transfer-Encoding)**です。Content-Encodingは「リソースそのものの表現」に対する圧縮で、ETagやキャッシュのキーと結びつく不可分な性質です。一方Transfer-Encoding(chunkedなど)はホップ単位の転送形式に過ぎません。実務で「圧縮」と呼ぶのはほぼ常に前者の Content-Encoding を指します。
Accept-Encodingによる方式交渉
どの圧縮方式を使うかは、クライアントとサーバーのコンテンツネゴシエーションで決まります。ブラウザはリクエストで対応方式を申告します。
GET /app.js HTTP/1.1
Accept-Encoding: br, gzip, deflate
サーバーは、自分が扱える方式とこの申告の積集合から1つを選び、応答で実際に使った方式を返します。同時に、選択がAccept-Encodingに依存することを下流のキャッシュへ伝えるためVaryを付けます。
HTTP/1.1 200 OK
Content-Encoding: br
Vary: Accept-Encoding
Accept-Encodingは品質値(q値)付きの優先度を表現でき、identity(無圧縮)を明示的に拒否することもできます。サーバー側の選択ロジックは「クライアントが受理可能 かつ 自分が生成可能 な方式のうち、圧縮率と負荷のバランスで望ましいものを選ぶ」という形になります。多くの構成では Brotli が使えれば Brotli、無ければ gzip、という優先順です。
Vary: Accept-Encoding が無いと、CDNや中間プロキシは「圧縮版」と「無圧縮版」を同一URLの単一エントリとして扱い、br非対応のクライアントへbr応答を返す(あるいはその逆)事故が起きます。圧縮を有効にしたら Vary の付与は必須です。ほとんどのサーバー実装は自動で付けますが、自前でヘッダを操作する場合は要注意です。
gzip(DEFLATE)の内部
gzip の中核はDEFLATEアルゴリズム(RFC 1951)で、2段構成です。
第1段はLZ77による辞書式圧縮です。直前までに出力したデータ列をスライディングウィンドウ(最大32KB)として保持し、これから出力する文字列がウィンドウ内の過去出現と一致すれば、その文字列を (距離, 長さ) の参照に置き換えます。同じトークンや属性名が繰り返すソースコードやマークアップで効果が大きいのは、この後方参照が働くためです。
第2段はハフマン符号化です。LZ77が生成したリテラルと参照の記号列を、出現頻度の高い記号ほど短いビット列へ割り当てて、全体のビット数を削ります。DEFLATEは各ブロックごとに頻度から最適なハフマン表を構築する動的ハフマンを使え、固定表との切り替えも可能です。
入力: the cat sat on the mat
LZ77: the cat s(距離4,長さ3)on (距離15,長さ4)mat ← "at "や"the "を後方参照に置換
ハフマン: 上記の記号列を頻度に応じた可変長ビットで符号化
ウィンドウが32KBに制限されるため、それより離れた位置にある重複は参照できません。これがDEFLATEの圧縮率上の根本的な天井であり、Brotliが超えにいった点でもあります。
Brotliの内部と差分
Brotli(RFC 7932)もLZ77系の後方参照とエントロピー符号化という骨格は共通ですが、3点で圧縮率を押し上げています。
(1) 大きなウィンドウ。最大ウィンドウは約16MBまで拡張でき(window bits で指定)、DEFLATEの32KBでは届かなかった遠方の重複も後方参照に取り込めます。大きなバンドルほど効きます。
(2) 静的辞書。Brotliは約120KBの組み込み辞書を持ち、Web上に頻出する語(<!DOCTYPE html>、function、</div> など)を初期状態から参照できます。さらに辞書語へ変換規則を適用する辞書変換を備え、語幹の語形変化なども参照に落とせます。小さなファイルでも「過去出力がまだ無い」初動から圧縮が効くのは、この静的辞書のためです。
(3) コンテキストモデルとエントロピー符号化の精緻化。直前の数バイトに応じて使うハフマン表を切り替えるコンテキストモデリングを持ち、DEFLATEより文脈適応的に符号長を最適化します。
| 観点 | gzip (DEFLATE) | Brotli |
|---|---|---|
| ウィンドウ最大 | 32KB | 約16MB |
| 静的辞書 | なし | 約120KBの組み込み辞書+変換 |
| 圧縮率(テキスト) | 基準 | 同等品質域で概ね15〜25%小さい |
| 品質レベル | 1〜9 | 0〜11 |
| 最高品質の圧縮速度 | 速い | 最高(11)は遅く動的向きでない |
| 展開速度 | 速い | gzipと同等に速い |
重要なのは、Brotliの優位は主に圧縮側にあり、展開(解凍)速度はgzipと同程度という点です。受信側の負担はどちらも軽いので、ブラウザでの展開コストは方式選択の決め手になりません。
品質レベルとCPUのトレードオフ
圧縮は「もっと縮める」ほど「もっとCPU時間を食う」関係にあります。これは探索の問題で、後方参照を探す範囲を広げ、より良い一致を粘り強く探すほど、出力は小さくなる代わりに計算量が増えるためです。
Brotliの品質は0〜11で、11は最高圧縮だが顕著に遅い。gzipは1〜9で、9でも比較的軽量です。ここで決定的なのは、圧縮は1回だけ行えば、その成果を多数の受信者が共有できるという非対称性です。1回の圧縮コストが配信回数で償却されるなら高品質が得、リクエストごとに圧縮し直すなら低〜中品質で抑える、という判断軸になります。
LZ77+エントロピー符号化の展開は、参照を辿ってバイトをコピーし可変長ビットを表引きするだけで、探索を伴いません。だから品質レベルを上げても展開時間はほぼ変わらず、コストは圧縮側に集中します。最適化は「圧縮を1回にまとめられるか」を軸に考えるのが正解です。
事前圧縮と動的圧縮の使い分け
この非対称性が、運用上の2方式に直結します。
**事前圧縮(静的圧縮)**は、ビルド時に成果物を最高品質で圧縮し、app.js.br と app.js.gz を生成しておく方式です。リクエスト時はサーバーがAccept-Encodingに応じて該当ファイルをそのまま返すだけで、配信時の圧縮CPUはゼロです。内容がデプロイ間で固定される静的資産(ハッシュ付きのCSS/JS/フォントなど)に最適で、ここでこそ Brotli 11 を使い切るべきです。
動的圧縮(オンザフライ圧縮)は、APIのJSONやSSRで生成したHTMLのように毎回中身が変わる応答を、その場で圧縮する方式です。同じ結果を再利用できないため、最高品質を使うとレスポンスごとにCPUを消費し、TTFBやスループットを悪化させます。実務では Brotli 4〜5 や gzip 6 程度の中程度の品質に抑え、圧縮率とレイテンシを釣り合わせます。
| 事前圧縮 | 動的圧縮 | |
|---|---|---|
| 対象 | ビルド成果物・静的資産 | API応答・SSRのHTMLなど可変応答 |
| 圧縮タイミング | ビルド時に1回 | リクエストごと |
| 推奨品質 | Brotli 11 / gzip 9(最高) | Brotli 4〜5 / gzip 6(中) |
| 配信時CPU | ゼロ(保存済みを返すだけ) | 毎回かかる |
| コスト償却 | 配信回数で償却される | 償却されない |
JPEG/PNG/WebP/AVIFや動画、Zip/Gzip済みアーカイブは既に高密度に圧縮済みで、再圧縮してもほぼ縮まないどころか、CPUを浪費しヘッダ分わずかに増えることすらあります。圧縮対象はテキスト系のMIMEタイプ(text/*、application/javascript、application/json、image/svg+xml など)に限定し、バイナリ画像・動画は除外するのが定石です。
数百バイト以下の応答は、圧縮で削れるバイトよりヘッダや方式自体のオーバーヘッドが相対的に大きく、CPUをかけても割に合いません。多くのサーバーは最小サイズ閾値(例: 1KB前後)を設け、それ未満は無圧縮で返します。試験や設計レビューでは「全応答を一律圧縮」が誤り、と判断できることがポイントです。
まとめ
コンテンツ符号化は、Accept-Encoding/Content-Encoding/Varyによる方式交渉を土台に、本文を可逆圧縮して転送量を削る仕組みです。gzipはLZ77(32KB窓)+ハフマンの汎用圧縮、Brotliは大きな窓・静的辞書・コンテキストモデルで同品質域なら高圧縮を出しますが、最高品質は圧縮CPUが重く、展開はどちらも軽い、という非対称性が鍵です。だからこそ静的資産は事前圧縮で最高品質を、可変応答は動的圧縮で中品質を選ぶ。転送を速くする全体像はWeb パフォーマンスを、再利用で通信を省く観点はHTTP キャッシュを、ヘッダ自体を圧縮する仕組みはHTTP/2の多重化とHPACKヘッダ圧縮の原理を併せて読むと、配信最適化の判断がつながります。
Web/フロントエンド Article
Brotli/gzipによるコンテンツ符号化と転送圧縮の原理を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
HTTP
比較で見る軸
難易度: advanced / カテゴリ: Web/フロントエンド / タグ数: 5
導入後に効く点
gzip/DEFLATEはLZ77+ハフマンの汎用圧縮、Brotliは静的辞書とコンテキストモデルで同じ品質域なら高圧縮を出すが、最高品質はCPUコストが重い。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- Web/フロントエンド
- タグ数
- 5
判断チェックリスト
- 自社の用途が「HTTP / Brotli」に近いか確認する。
- 強みである「Content-Encodingはブラウザの Accept-Encoding 申告とサーバーの応答ヘッダで圧縮方式を合意し、本文を符号化して転送量を減らす仕組み。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。