- はじめに — 最後のピースが埋まった
- 対応状況マトリクス — zstdと圧縮辞書は状況が違う
- zstdが実際にもたらすもの — 数字は条件とセットで
- サーバー側はまだ非対称
- 次のステップ — RFC 9842 圧縮辞書転送
- 実測値 — 静的フローと動的フロー
- 辞書が答えにならないとき
- 実務判断
- おわりに
- 参考資料
はじめに — 最後のピースが埋まった
2026年2月11日に公開されたSafari 26.3のリリースノートには、こんな一文があります。原文のまま引用すると — "Added support for Zstandard content encoding in Safari 26.3 for iOS, iPadOS, visionOS, and macOS 26.3."(Apple リリースノート)
この一文で状況が変わります。Content-Encoding: zstdはChrome 123(2024年3月)、Firefox 126(2024年5月)がすでに対応しており、残る大きなピースがSafariでした。これで3大ブラウザエンジン(Blink、Gecko、WebKit)すべてが、zstdで圧縮されたHTTP応答を受け取れるようになります。HTTP転送圧縮の標準的な選択肢が、gzip、brotliに続いて3つに増えたことが、実質的に完成したわけです。
もちろんキャビアットから先に書いておきます。WebKitブログによれば、Safari 26.3のzstdはiOS/iPadOS/visionOS 26.3およびmacOS Tahoe 26.3で動作し、旧バージョンのmacOS上で動くSafari 26.3では動作しません(システムのネットワーキングスタックに依存するため)。そのためcaniuseの集計も、Safari 26.3を「macOS 26.3以上が必要」という注記付きで部分対応に分類しています — 本稿執筆時点の参照では、全面対応ブラウザのシェアは約79.5%、部分対応は約2.1%です。
とはいえ、導入リスク自体は低いです。圧縮はAccept-Encodingネゴシエーションで決まるため、zstdを受け取れないクライアントにはbrotliやgzipへ自動でフォールバックします。オンにして壊れる箇所はなく、オフのままなら得られる利得もありません。
対応状況マトリクス — zstdと圧縮辞書は状況が違う
MDNのブラウザ互換性データを基準にまとめるとこうなります。
| 機能 | Chrome | Firefox | Safari |
|---|---|---|---|
Content-Encoding: zstd | 123 (2024-03) | 126 (2024-05) | 26.3 (2026-02) |
dcb / dcz(圧縮辞書、RFC 9842) | 130 (2024-10) | 未対応 | 未対応 |
上段が今回完成した話で、下段が本稿後半の話です。圧縮辞書転送は2025年9月にRFC 9842として発行されました(著者はGoogleのP. Meenan、ShopifyのY. Weiss)が、現時点ではChromium系のみが出荷しています。ただしMozillaは公式にpositive、WebKitはsupportの立場を表明済みなので、反対によって止まっているわけではありません。
zstdが実際にもたらすもの — 数字は条件とセットで
zstdプロジェクトがREADMEで公開している自前のベンチマークを、条件そのままに転載します。Core i7-9700K @ 4.9GHz、Ubuntu 24.04、gcc 14.2.0、lzbench(インメモリ)、Silesiaコーパス — つまりプロジェクト自身の測定であり、ディスクやネットワークを介さない純粋なCPUスループットの数値です。
| 圧縮器(レベル1系) | 圧縮率 | 圧縮速度 | 解凍速度 |
|---|---|---|---|
| zstd 1.5.7 -1 | 2.896 | 510 MB/s | 1550 MB/s |
| brotli 1.1.0 -1 | 2.883 | 290 MB/s | 425 MB/s |
| zlib 1.3.1 -1 | 2.743 | 105 MB/s | 390 MB/s |
この表で見るべきは順位ではなく、差の性質です。同じ「高速レベル」帯で、zstdはzlibより圧縮が約5倍、解凍が約4倍速く、それでいて圧縮率はむしろ高い。だからzstdの定番の使いどころは、動的応答のon-the-fly圧縮です — WebKitブログもまさにこの枠組みで紹介しています。brotliは通常、ビルド時に静的アセットを最高レベルで事前圧縮しておく用途に使い、リアルタイムに圧縮しなければならないAPI応答やHTMLには、CPU予算の観点でzstdが有利ということです。なお、この表はレベル1基準なので、「brotli最高レベルとの圧縮率比較」といった主張はここから導けません — アルゴリズムの内部(LZ77、ANS、Huffman)が気になる方は圧縮アルゴリズム Deep Dive編をどうぞ。
HTTPの外では、すでに実証済みの置き換えです。Discordはゲートウェイ(WebSocket)の圧縮をzlibストリーミングからzstdストリーミングに切り替え、MESSAGE_CREATEペイロードの圧縮率が6から10近くまで上がり、平均サイズが270バイトから166バイトに減ったと自社の測定値を公開しました(2024年ロールアウト)。彼らが言う「ゲートウェイ帯域幅の約40%削減」は、zstd単独ではなく別途のpassive sessions最適化と合算した数値であることが、原文に明記されています。
ライブラリ自体のリリース状況も触れておくと — 最新リリースはv1.5.7(2025-02-19)で、devブランチのCHANGELOGにはv1.6.0の項目(レガシーフォーマット対応をデフォルトで無効化)が用意されていますが、2026年7月17日時点でタグもGitHubリリースも出ていません。
サーバー側はまだ非対称
ブラウザが全部受け取れるようになっても、それで終わりではありません。送る側の地形はこうです(2026年7月時点、各プロジェクトの公式ドキュメント・変更履歴で確認)。
- nginx — 公式のzstdモジュールがありません。公式ドキュメントのモジュール一覧にzstdは登場せず、使うにはサードパーティ製モジュールを自前でビルドする必要があります。
- Apache httpd — 2.4.x系のCHANGESにzstdの項目がありません。公式対応はmod_brotliまでです。
- Caddy —
encodeディレクティブがzstdに対応しています。 - Node.js — v23.8.0(2025-02-13)以降、
node:zlibにzstdの圧縮・解凍APIが入りました。アプリレベルで直接扱えます。 - CDN — Cloudflareは全プランでZstandardに対応しており、Freeプランではデフォルトの圧縮がZstandardです(brotli・zstdともに応答が最低50バイトという条件があります)。
まとめると、オリジンがnginx/httpdなら、今日いちばん近道なのはCDN側でオンにすることです。二大主要Webサーバーに公式モジュールがないという事実が現在のzstd普及の実質的なボトルネックであり、「ブラウザ対応の完成」と「サーバーエコシステムの完成」のあいだの時差こそが、このテーマの現在地です。
次のステップ — RFC 9842 圧縮辞書転送
zstd対応の完成が第1幕だとすれば、第2幕は辞書(dictionary)圧縮です。発想はシンプルです。圧縮アルゴリズムは「すでに見たデータ」を参照して次のデータを縮めますが、ブラウザはすでに多くを保持しています — 昨日受け取ったJSバンドル、同じサイトの別のHTML。それを辞書として使えば、事実上デルタだけを転送すればよくなります。
RFC 9842が定義するフローを概念例として描くとこうなります。
# 1) 初回訪問 - サーバーがこの応答を辞書として登録するよう伝える
GET /js/app.v133.js
<- 200 OK
<- Content-Encoding: br
<- Use-As-Dictionary: match="/js/app*.js"
# 2) 次回訪問 - ブラウザが保持する辞書のハッシュを提示する
GET /js/app.v134.js
-> Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:
-> Accept-Encoding: gzip, br, zstd, dcb, dcz
# 3) サーバーはその辞書で圧縮したデルタだけを送る
<- 200 OK
<- Content-Encoding: dcb
別途の辞書リソースを<link rel="compression-dictionary">で配信する経路もあります。新しいコンテンツエンコーディングは2種類で、dcbは4バイトのマジックナンバーと辞書のSHA-256ハッシュ(32バイト)に続けてShared Brotliストリームが来る形式(クライアントは最大16MBウィンドウの解凍に対応する義務がある)、dczはzstdのskippable frameとして設計された40バイトヘッダーの後に辞書適用済みzstdストリームが続く形式です — クライアントは8MBか辞書サイズの1.25倍のうち大きいほう(上限128MB)までのウィンドウに対応する必要があります。キャッシュ可能な応答であればVary: accept-encoding, available-dictionaryが必須です — 辞書が別のクライアントに誤って配信されるのを防ぐためです。詳細はRFC 9842の4章・5章にあります。
実測値 — 静的フローと動的フロー
数字は2種類に分けて見る必要があります。それぞれに出典と条件を添えます。
静的フロー(旧バージョンを辞書に)。 基準になるのは、RFC共著者Meenanが公開したテスト集です。著者自身の測定で、brotli CLIレベル5、「辞書 = 同一リソースの旧バージョン」という条件です。
- YouTubeデスクトッププレーヤーのJS(10MB、非圧縮): brotli単独で1.8MB → 2か月前のバージョンを辞書にすると384KB(78%削減)。週次リリース間隔なら172KB(90%削減)。
- CNNのヘッダーバンドル(278KB): brotli単独で90KB → 1年前のバージョンを辞書にして2KB(98%削減)。
- Wikipediaのようにテキスト中心ですでによく圧縮されているページは、改善幅がずっと小さかったと同じ文書に記載されています。
動的フロー(パス専用のカスタム辞書)。 ここには実運用の数字があります。Google検索は検索結果ページのHTMLに共有brotli辞書を配布し、その結果をChromeブログで公開しました(2025年5月14日、ベンダー自己測定)。代表サンプルから辞書を作り、1日に何度も更新する自動パイプラインを回した条件で —
- Chrome利用者全体でHTMLペイロードが平均23%削減。この平均には、辞書をまだ持たない初回訪問ユーザーも含まれます。
- 辞書がヒットした応答だけを見ると、50%近い削減。
- 体感指標としてはLCP改善が全体で1.7%、高遅延ネットワークでは最大9%。
最後の一行が、本稿でいちばん正直な数字だと思います。転送バイト数が数十パーセント減っても、世界でも指折りに最適化されたページのLCPは1.7%しか良くなりません。圧縮の削減率と体感速度は等価ではありません — 特に帯域幅がボトルネックでない環境では。逆に、高遅延・低帯域環境で最大9%というのは、この手法の価値がユーザー分布によって大きく変わることも意味します。
辞書が答えにならないとき
バランスを取るために、失敗事例もひとつ。Discordは上記のzstd移行の過程で、辞書も試しています — 12万件の匿名化したメッセージで、JSON用・ETF用の辞書を2つ訓練しました。オフライン評価では、小型ペイロードが636バイトから187バイトに縮み(辞書なしでは466バイト)有望に見えましたが、プロダクションでは結果がまちまちでした。2.5MBのREADYペイロードは辞書を使っても約600バイトしか追加で縮まず、MESSAGE_CREATEはむしろ悪化しました。結論は辞書の撤回 — 「辞書がもたらすわずかな圧縮改善は、ゲートウェイとクライアントに加わる複雑さに見合わなかった」というのが彼らの総括です。
理由は構造的です。Discordの接続はストリーミング圧縮のコンテキストが生きているため、接続が続いている間、圧縮器はすでに「過去のデータから学習」しています。辞書が助けになるのは、ストリームの最初の数KBだけです。zstdプロジェクトのドキュメントも同じことを言っています — 辞書の利得は小さなデータの最初の数KBに集中し、万能の辞書は存在せず、データタイプごとに個別に訓練する必要があります。
HTTP側の辞書圧縮(RFC 9842)にも固有のコストがあります。
- 運用パイプライン。 Googleの事例の前提は、1日に何度も辞書を再生成・再配布する自動化です。コンテンツが変わるのに辞書が古いままだと、利得は減ります。ビルド・配信経路に辞書のバージョニングが追加されます。
- プライバシー規定。 辞書のハッシュが追跡クッキーとして悪用されうるため、RFCの10章はクライアントに、辞書をクッキーと同様に扱うことを要求しています — クッキーと同水準(かそれ以上)のパーティショニング、クッキー削除時には辞書も削除。つまり辞書のヒット率はクッキーの寿命を超えられません。
- セキュリティ制約。 混在ソース圧縮攻撃(CRIME/BREACH系、RFC 7457)への配慮が辞書にもそのまま当てはまります — 辞書にユーザーデータを入れてはならず(Discordも訓練データを匿名化しました)、辞書のマッチングはsame-originに制限され、オリジンをまたぐ場合はCORSの通過が必須です。
- ブラウザカバレッジ。 繰り返しになりますが、現状はChromium系のみです。Firefox/Safariユーザー向けには通常の圧縮経路を維持し続ける必要があるため、辞書圧縮は「追加のパイプライン」であって置き換えではありません。
実務判断
今すぐオンにするもの — Content-Encoding: zstd。 ネゴシエーションベースのフォールバックのおかげでリスクは低く、ブラウザカバレッジは今回のSafari 26.3で実質的に埋まりました。CDNの背後にいるなら設定スイッチひとつです。オリジンで直接やるなら、nginx/httpdに公式モジュールがないことが現実的な障害なので、Caddy・Nodeアプリレベル・CDNのうち自分のスタックに合う経路を選べばよいです。動的応答(on-the-fly)が主戦場で、静的アセットの事前圧縮は既存のbrotliパイプラインを維持しても構いません。
計算してから決めるもの — dcb/dcz。 リピート訪問の比率が高く、JSバンドルが大きく、リリース頻度が高いサービスなら、Chromiumのシェア分の削減だけでも採算が合うことがあります。上の実測のように、デルタ転送は桁違いの削減をもたらすからです。ただし、辞書生成・バージョニングのパイプラインと二重配信経路を担えるチームである必要があり、削減バイト数ではなく自社サービスの体感指標(LCPなど)で利得を検証する必要があります — Googleでさえ全体のLCP改善は1.7%でした。
やらないこと。 トラフィックが小さい、あるいはユーザーの再訪が少ないサイトが辞書インフラから作り始めること。すでにストリーミング圧縮のコンテキストがあるカスタムプロトコルに辞書を載せること(Discordの教訓)。そして、ベンダーの削減率を自社サービスの性能改善と同一視すること。
おわりに
まとめるとこうです。Safari 26.3(2026年2月11日)でContent-Encoding: zstdのブラウザパズルは埋まり、残る非対称はサーバーエコシステム(二大主要Webサーバーに公式モジュールがないこと)です。次のステップであるRFC 9842の辞書圧縮は、標準化(2025年9月)と実運用検証(Google検索、ベンダー自己測定で平均23%のペイロード削減)まで済んでいますが、ブラウザはまだChromiumのみで、運用コストとプライバシー規定は現実の制約として存在します。zstdは今日オンにし、辞書は自分のトラフィックで採算計算をしてから。圧縮率は手段であり、指標は常にユーザー側にあります。
参考資料
- Safari 26.3 Release Notes — Apple Developer
- WebKit Features in Safari 26.3 — webkit.org
- RFC 9842 — Compression Dictionary Transport
- Content-Encoding — MDN(ブラウザ互換性表)
- zstd (Zstandard) content-encoding — caniuse
- facebook/zstd — Benchmarks(プロジェクト自己測定)
- Compression dictionary transport examples — WICG(著者自己測定)
- How Google Search made their results pages 23% smaller — Chrome for Developers(ベンダー自己測定)
- How Discord Reduced Websocket Traffic by 40% — Discord(ベンダー自己測定)
- Zstd Content-Encoding — Chrome Platform Status
- Compression dictionary transport — Chrome Platform Status
- Mozilla standards-positions #771 (positive) · WebKit standards-positions #160 (support)
- Node.js v23.8.0 — node:zlib zstd対応
- Cloudflare compression ドキュメント · Caddy encode ディレクティブ
- 圧縮アルゴリズム Deep Dive — LZ77, zstd, brotli, ANS, Huffman(関連記事)
현재 단락 (1/74)
2026年2月11日に公開されたSafari 26.3のリリースノートには、こんな一文があります。原文のまま引用すると — "Added support for Zstandard content e...