ZSTD vs Brotli vs GZIP:API 圧縮の選び方
ZSTD、Brotli、GZIP を API 圧縮で比較:圧縮率、速度、CPU/メモリコスト、JSONやバイナリの実運用上のデフォルトとチューニング。

API圧縮とは(いつ有効か)
APIのレスポンス圧縮とは、サーバーがレスポンスボディ(多くはJSON)をネットワーク送信前に小さなバイト列にエンコードし、クライアント(ブラウザ、モバイルアプリ、SDK、別サービスなど)がそれを復元することです。HTTP上では、これは Accept-Encoding(クライアントが対応するもの)と Content-Encoding(サーバーが選んだもの)といったヘッダーでネゴシエートされます。
APIにとっての効果
圧縮で得られる主な利点は3つです:
- 帯域の削減: 小さなレスポンスはエンドツーエンドで消費バイトを減らします。
- 帯域が制約されるリンクでのレイテンシ低下: モバイルや混雑したWi‑Fi、リージョン間通信では、少ないバイト数はしばしば高速なダウンロードにつながります。
- 送信コストの低下: 転送量に課金がある場合、サイズ削減は直接コスト削減になります。
トレードオフは明確で、圧縮は帯域を節約しますがCPU(圧縮/復元)と場合によってはメモリ(バッファ)を消費します。メリットはどのリソースがボトルネックかによります。
圧縮が有効なケース
圧縮は次のようなレスポンスで力を発揮します:
- テキスト中心で繰り返しが多いもの(JSON、GraphQLの応答、HTML、ログなど)
- 中〜大サイズで、数十〜数百KBの削減に意味がある場合
- 遅い/高コストなネットワーク(モバイル、国際クライアント、リージョン間)に配信する場合
大きなJSONリスト(カタログ、検索結果、分析データ等)を返すなら、圧縮は簡単に得られる改善策の一つです。
圧縮が向かないケース
圧縮はCPUを消費するため、次のような場合は効率が悪いです:
- 非常に小さいレスポンス(数百バイトなど)。ヘッダーとCPUオーバーヘッドが節約額を上回ることがある。
- 既に圧縮されているデータ(JPEG/PNG、MP4、ZIP、多くのPDF)。再圧縮してもほとんど縮まらず、場合によってはサイズが増えることもある。
- CPUがボトルネックのサービス(ホットエンドポイントで計算負荷が高い)。圧縮を追加すると尾部レイテンシが悪化する可能性がある。
このガイドで使う判断軸
ZSTD vs Brotli vs GZIP を選ぶ際の実用的な判断は通常次の3つに集約されます:
- サイズ削減(圧縮率)
- レイテンシ(サーバーのバイト送信開始までの時間+クライアントでのデコード時間)
- クライアントの対応状況(呼び出し元や経路上の中間装置が確実に対応するか)
以下は、これらをトレードオフしてあなたのAPIとトラフィックに最適化するための実践的な説明です。
ZSTD vs Brotli vs GZIP: クイック比較
3つともペイロードを小さくしますが、速度・圧縮率・互換性のどれを重視するかで得意分野が異なります。
一目での要約
- ZSTD (Zstandard): レイテンシ重視でCPUが予測可能に使える場合にAPIの標準として優秀。良好な圧縮率を保ちつつ遅くなりにくい。
- Brotli: テキスト中心のレスポンス(JSON、HTMLなど)で最小のバイト数を達成することが多い。高レベルはCPUコストが高い。
- GZIP: 「どこでも動く」オプション。互換性が広く運用が簡単だが、同等のCPU予算ではモダンな代替より遅いかサイズが大きいことが多い。
典型的な強み(APIにとっての意味)
ZSTDの速度: エンドポイントの尾部レイテンシに敏感なときやサーバーがCPUに制約があるときに有利。中〜大サイズのJSONでは、圧縮が十分に速くネットワーク時間に比べて無視できることが多い。
Brotliの圧縮率: 帯域が主要な制約(モバイル、egressコスト、CDN配信)でテキスト中心のレスポンスが多い場合に最も有効。小さなペイロードでも長めの圧縮時間に耐えられるなら価値がある。
GZIPの互換性: 最大限のクライアント互換性が必要な場合(古いSDK、組み込みクライアント、レガシープロキシ)に最適。性能面でトップではないが安全なベースラインとなる。
「圧縮レベル」が実際に変えるもの
圧縮の“レベル”はCPU時間と出力サイズのトレードオフを示すプリセットです:
- 低レベル: 圧縮が速く、出力は大きめ。リアルタイムAPI向け。
- 高レベル: 出力は小さくなるが圧縮が遅い(場合によってはメモリも増える)。大きくキャッシュ可能なレスポンス向け。
復号は通常どれも圧縮よりずっと安いですが、非常に高いレベルはクライアント側のCPU/バッテリーにも影響します。
単純な経験則
- デフォルト: レイテンシを重視する多くのJSON/REST/GraphQL APIでは ZSTD を使う
- Brotliに切替: 最小バイト数が最重要で、テキスト中心かつCDN配信や遅いネットワーク向けの場合
- GZIPを維持: 多様なクライアントと互換性を確保する必要がある、あるいはインフラが新しいエンコーディングをサポートしていない場合
圧縮率とレイテンシ: 中核のトレードオフ
圧縮は「レスポンスが小さければAPIは速くなる」と言われますが、それは常に正しいわけではありません。圧縮処理がサーバーのCPU時間を増やすと、実際には応答が遅くなることがあります。
時間のかかる部分を分解すると
2つのコストに分けると分かりやすいです:
- 圧縮時間(サーバー側): サーバーが最初のバイトを送る前に行う作業。これが直接レスポンス時間(TTFB)に加算される。
- 復号時間(クライアント側): 受信後にクライアントが行う作業。通常は圧縮より安いが、低電力デバイスや高スループットクライアントでは影響する。
高い圧縮率は転送時間を短縮しますが、圧縮が1レスポンスあたり15–30msを追加するなどすると、高速接続では節約分を上回って遅くなることがあります。
負荷時の尾部レイテンシの罠
負荷が高いと、圧縮はp95/p99レイテンシを悪化させることが多いです。CPU使用率が上がるとリクエストが待たされ、キューイングは小さな追加コストを大きな遅延に増幅します。平均レイテンシは悪化しない場合でも、最悪の影響を受けるユーザーが発生します。
パフォーマンス機能として計測する
推測で判断せず、A/Bテストや段階的ロールアウトで次を比較してください:
- p50, p95, p99 レイテンシ
- APIインスタンスのCPU利用率と飽和度
- レスポンスサイズとTime-to-First-Byte
実際のトラフィックとペイロードでテストし、最終的に選ぶべき圧縮レベルは「合計時間が短くなる」ものです。単にバイト数が減るだけでは不十分です。
サーバーとクライアントのCPU・メモリコスト
圧縮は“無料”ではありません — 両端でCPUとメモリが増えます。APIでは、リクエスト処理時間の増加、ピークメモリの増加、クライアント側の低速化として現れます。
CPUが使われる場所
多くのCPUはレスポンスの圧縮に使われます。圧縮はパターン探索、状態や辞書の生成、出力のエンコードを書き出す作業を含みます。
復号は通常安価ですが重要です:
- サーバーは(まれに)リクエストを解凍することがある(アップロードやバッチ処理で頻出)
- クライアントは受信したらまず復号してからJSONをパースするため、復号は重要なクリティカルパスになります
アプリサーバーが既にCPUで逼迫しているなら、高い圧縮レベルはp95/p99を悪化させることがあります。
メモリの注意点
圧縮は次のようにメモリ消費を増やすことがあります:
- バッファ: 実装は入力/出力バッファを必要とし、大きなペイロードは大きなバッファを要求する
- フルバッファリング vs ストリーミング: ストリーミング圧縮は早く送信を開始できピークメモリを抑えられるが、フルバッファリングはリクエストごとのピークメモリを膨らませる
コンテナ環境ではピークメモリの増加がOOMやデプロイ密度の低下につながることがあるので注意してください。
オートスケールやコンテナ制限への影響
圧縮はレスポンスごとにCPUを消費するため、インスタンス当たりのスループットが下がり、オートスケールが早く発動してコストが上がることがあります。帯域が減ってもCPU消費が増えるため、どのリソースが不足しているかにより選択が変わります。
クライアント側の復号速度が重要な理由
モバイルや低消費電力デバイスでは、復号がレンダリングやJS実行、バッテリー消費と競合します。数KBを節約しても復号が長時間かかるフォーマットは「体感上遅い」と感じられることがあります。
ZSTD(Zstandard): 強み・制限・実用的なデフォルト
ZSTDは、良好な圧縮率を保ちながらAPIの速度を著しく損なわないように設計されたモダンなフォーマットです。多くのJSON中心のAPIでは、GZIPより小さなレスポンスを同等または低いレイテンシで提供できるため「デフォルト」として有力です。
ZSTDが得意なこと
エンドツーエンド時間を重視する場合に最も有用です。圧縮が速く、復号は非常に高速で、リクエスト処理時間の競合が激しい環境で役立ちます。
小〜中サイズのJSONでも有意な改善が期待でき、大きなレスポンスではさらに効果的です。
API向けの妥当な圧縮レベル
ほとんどのAPIでは低めのレベル(一般的に1–3)から始めてください。これらはレイテンシとサイズのバランスが良いことが多いです。
次のような場合に高レベルを検討します:
- ペイロードが大きい(数百KB〜MB)
- 帯域が高コスト/制約がある
- CPUがボトルネックでないことが計測で確認できる
実務的にはグローバルな低いデフォルトを採り、特定の“大きなレスポンス”エンドポイントだけレベルを上げるのが良いアプローチです。
ストリーミングと辞書モード
ZSTDはストリーミングをサポートしており、大きなレスポンスでピークメモリを抑えつつ早くデータを送れる利点があります。
辞書モードは、似たオブジェクトを頻繁に返すAPI(繰り返すキー、安定したスキーマ)に対して大きな利得をもたらすことがあります。小さくて頻繁に送られるペイロードに対して、バージョン管理された辞書を運用できれば効果的です。
互換性の限界
多くのサーバースタックでサポートは容易ですが、クライアント互換性が決定要因になることがあります。いまだに Content-Encoding: zstd をデフォルトで広告しないHTTPクライアント、プロキシ、ゲートウェイもあります。
サードパーティのコンシューマがいる場合は、フォールバック(通常はGZIP)を用意し、Accept-Encoding に zstd が含まれている場合にのみ有効にしてください。
Brotli: 勝てる場面と向かない場面
Brotliはテキストを非常に効率よく縮めるよう設計されています。JSONやHTMLのような“語彙的”なペイロードではGZIPより良い圧縮率を出すことが多く、特に高いレベルで顕著です。
Brotliが勝つ場面
テキスト中心のレスポンスがBrotliの得意分野です。大きなJSONドキュメント(カタログ、検索結果、設定塊)を送る場合、Brotliはバイト数を大幅に削減でき、遅いネットワーク上やegressコスト削減に寄与します。
また、一度圧縮して多数回配信する(キャッシュ可能なレスポンス、バージョン付きリソース)のような場面では、高いBrotliレベルがCPUコストを複数リクエストで償却できるため有効です。
Brotliが期待はずれになる場面
動的なAPIレスポンス(リクエストごとに生成される)では、Brotliの最良の圧縮率を得るには高いレベルが必要で、それがCPUコストとレイテンシ増加を招きます。現実の運用では、ZSTDや適切にチューニングされたGZIPとの差は思ったほど大きくないことがあります。
すでに圧縮されているペイロードや多くのバイナリ形式では有効性が低く、CPUを無駄にするだけです。
実用的なレベル指針
- ランタイム圧縮: レベル 1–4 を使い、CPUスパイクを避ける
- 事前圧縮/静的: レベル 8–11 はリクエスト数でコストを分散できるなら検討に値する
クライアント対応メモ
ブラウザはHTTPS経由でBrotliを比較的良くサポートするため、ウェブトラフィックでは人気があります。非ブラウザのAPIクライアント(モバイルSDK、IoT、古いHTTPスタック)では対応が不安定な場合があるので、Accept-Encoding によるネゴシエーションと gzip のフォールバックを忘れないでください。
GZIP: 互換性と実際の性能
GZIPは、ほとんどすべてのHTTPクライアント、ブラウザ、プロキシ、ゲートウェイが理解するため、今もなおデフォルト回答として残っています。完全にコントロールできない経路やクライアントがいる場合、予測可能性が重要です。
普及している理由
GZIPの優位性は“最良”であることではなく、“間違いになりにくい”点です。多くの組織が長年の運用経験を持ち、ウェブサーバーに合理的なデフォルトがあり、中間装置が新しいエンコーディングを壊すリスクが低いことも利点です。
API向けの実用的な圧縮レベル
APIペイロード(多くはJSON)では、中〜低レベルが最適です。レベル1–6は多くの場合サイズ削減の大部分を提供しつつCPUも抑えます。非常に高いレベル(8–9)はわずかなサイズ改善しかもたらさないため、動的なリクエスト/レスポンスでは通常割に合いません。
モダンなCPU上での比較
最新のハードウェア上では、GZIPは同等の圧縮率に対してZSTDより遅いことが多く、テキストに対してBrotliの最高圧縮率にも届かないことがよくあります。実ワークロードでは:
- ZSTD はバイト削減あたりの速度で優位になることが多い
- Brotli は非常に圧縮しやすいテキストでサイズ優位になるがCPUコストが要注意
- GZIP は多様なスタックで最適化されているため「十分速い」ことが多い
互換性上の例外
古いクライアント、組み込みデバイス、企業プロキシ、レガシーゲートウェイが相手だと、GZIPが最も安全です。一部の中間装置は未知のエンコーディングを剥がしたりパススルーしなかったりするため、環境が混在している場合はまずGZIPで開始し、完全にパスが管理できる部分でZSTDやBrotliを追加するのが良い戦略です。
ペイロード種類: よく圧縮されるもの・されないもの
アルゴリズムだけでなく、送るデータの種類が圧縮効果の最大要因です。あるペイロードは劇的に縮み、あるものはほとんど変わりません。
効果が高い候補
テキスト中心で繰り返しが多いものは非常によく縮みます:
- JSON(典型的なREST応答)
- GraphQL応答(フィールド名の繰り返しが多い)
- XML、HTML
- 大きなプレーンテキストログやトレース
繰り返しと構造が多いほど圧縮率は良くなります。
バイナリペイロード: "場合による"(まず測定)
ProtobufやMessagePackのようなバイナリ形式はJSONよりコンパクトですが“ランダム”というわけではありません。繰り返しタグや類似のレコード構造を含むことが多く、大きめのレスポンスやリスト中心のエンドポイントでは圧縮効果があることが多いです。確実なのは実データでテストすることです。
通常は圧縮の価値が小さい(既に圧縮済み)
内部的に圧縮を使っている形式に対してHTTP圧縮を上書きしてもほとんど削減効果がなく、レスポンス時間を悪化させることがあります:
- 画像: JPEG, PNG, WebP
- 動画/音声: MP4 等
- アーカイブ: ZIP, gz など
- PDF: 多くは既に圧縮を使う
これらはContent-Typeベースで圧縮を無効にするのが一般的です。
実用的なヒューリスティック
単純に次を適用するのが有効です:
- 圧縮はある最小レスポンスサイズを超えた場合にのみ有効化する(例: 数KB)
- 大きなテキストレスポンスは常に圧縮する。小さなJSONはヘッダが支配するためスキップすることを検討する
こうすることでCPUを実際に効果があるペイロードに集中させられます。
HTTPヘッダーとネゴシエーション: 正しく設定する
圧縮はクライアントとサーバーがエンコーディングで合意して初めてスムーズに動きます。合意は Accept-Encoding(クライアント送信)と Content-Encoding(サーバー送信)で行われます。
Accept-Encoding と Content-Encoding(簡単な例)
クライアントがデコード可能なものを宣言します:
GET /v1/orders HTTP/1.1
Host: api.example
Accept-Encoding: zstd, br, gzip
サーバーはひとつを選んで宣言します:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Encoding: zstd
もしクライアントが Accept-Encoding: gzip と送っているのにサーバーが Content-Encoding: br を返すと、そのクライアントはボディをパースできない可能性があります。クライアントが Accept-Encoding を送っていない場合、最も安全なのは圧縮を行わないことです。
サーバー側の優先順位の設定
実用的な順序の一例:
- まず
zstd(速度と比率のバランスが良い) - 次に
br(テキストでより小さくなることが多い) - 最後に
gzip(最も互換性が高い)
つまり一般には zstd > br > gzip の順です。ただしトラフィックがブラウザ中心なら br を上位にする、古いモバイルクライアントが多ければ gzip を優先する、といった調整が必要です。
Vary: Accept-Encoding とキャッシュ
複数のエンコーディングで同じレスポンスを提供しうる場合は、次を追加してください:
Vary: Accept-Encoding
これがないとCDNやプロキシがあるエンコーディングをキャッシュして、別のデコーダしか持たないクライアントに誤って返してしまう恐れがあります。
エッジケースと安全なフォールバック
一部のクライアントはサポートを主張していてもデコーダがバグっていることがあります。堅牢にするために:
zstd関連のデコードエラーが増えたら一時的にgzipにフォールバックする- 問題を起こすユーザーエージェントやSDKバージョンを許可リスト/除外する
- 認証やウェブフックのような重要エンドポイントでは圧縮を無効化するか最も互換性の高いオプションのみ許可する
ネゴシエーションはバイトを最大限削ることより「クライアントを壊さない」ことが重要です。
HTTP/2、HTTP/3、CDN、ゲートウェイ
圧縮は単独では動作しません。トランスポートプロトコル、TLSのオーバーヘッド、CDNやゲートウェイの動作は実際の挙動を変え、誤設定だと動作を壊すことすらあります。
HTTP/2 と HTTP/3: マルチプレクシングと圧縮の影響
HTTP/2では複数のリクエストが単一のTCP接続を共有します。接続オーバーヘッドは減りますが、パケットロスが発生するとTCPのヘッドオブラインブロッキングで複数ストリームが停滞することがあります。圧縮はレスポンスボディを小さくしてこの影響を減らすのに役立ちます。
HTTP/3はQUIC上で動き、ストリーム間でTCPレベルのヘッドオブライン問題がないため、損失時の影響が少ない傾向にあります。それでもペイロードサイズは重要で、圧縮は帯域削減や「最後のバイトまでの時間」短縮として効果を発揮します。
TLSとの相互作用: CPU予算を無視しない
TLS自体もCPUを消費します(ハンドシェイク、暗号/復号)。高レベル圧縮を加えるとピーク時にCPU予算を超えることがあるため、実運用では「速い圧縮でまずは良好な比率を得る」設定が有利なことが多いです。
CDNとAPIゲートウェイ: 自動圧縮、パススルー、または剥奪
CDNやゲートウェイの中には特定のMIMEタイプに自動で圧縮を適用するもの、オリジンからの Content-Encoding をそのまま通すもの、ヘッダーを変更してしまうものがあります。ルートごとの挙動を確認し、Vary: Accept-Encoding が保持されることを確認してください。
キャッシュ戦略: エッジ vs オリジン(多重バリアント)
エッジでキャッシュする場合はエンコーディングごとに別バリアントを保存する(gzip/br/zstd)方がよいです。オリジンでキャッシュする場合でも、エッジがネゴシエートして複数エンコーディングをキャッシュする構成を検討してください。重要なのは整合性です:正しい Content-Encoding、Vary、圧縮の責務の明確化。
推奨デフォルトとチューニング手順
シナリオ別の推奨
- ブラウザ向けAPI: クライアントが
Accept-Encoding: brを送るなら Brotli を優先。ブラウザはBrotliの復号を効率的に行い、テキストでのサイズ削減が期待できる。 - 社内のサービス間API: 両端を管理できるなら ZSTD をデフォルト。ZSTDはGZIPより高速で同等か優れた比率を出しやすい。
- 多様な公開API: 広範な互換性のために GZIP をベースに保ち、クライアントが明示的に対応する場合にZSTDをオプトインで提供するのが現実的。
保守的な開始レベル
まずは安全側のレベルから始める:
- Brotli: 動的レスポンスは 4–6(高レベルはサーバーCPUを顕著に増やす)
- ZSTD: 一般用途は 3–5
- GZIP: 5–6 が良いデフォルト(高レベルは効果が小さい)
より強い圧縮が必要なら、プロダクションに近いサンプルでp95/p99を観測してから上げてください。
最小サイズ閾値(とチューニング)
小さいレスポンスを圧縮するとCPUが節約分を上回ることがあります。実用的な開始点:
- 1–2 KB未満は圧縮しない
- CPUが逼迫しているかチャッティなAPIなら 4 KB を検討
比較対象は (1) 削減バイト数、(2) 追加されたサーバー処理時間、(3) エンドツーエンドのレイテンシ変化です。
安全にコントロールを公開する方法
圧縮を機能フラグの背後に置き、段階的に有効化します。ルート単位の設定(/v1/search は有効、既に小さいエンドポイントは無効)を用意し、クライアントのトラブルシュート用に Accept-Encoding: identity でオプトアウトできるようにします。キャッシュを正しくするために常に Vary: Accept-Encoding を含めてください。
現代の開発ワークフローでの現れ方
素早くAPIを生成してデプロイするワークフローでは(例えばReactフロントエンド+Goバックエンドのような)、圧縮は「小さな設定で大きな影響」を与えるチューニングポイントです。プロダクトが安定してきたら(ペイロード形状が見えてきたら)圧縮とキャッシュヘッダーをチューニングするのが現実的アプローチです。
ロールアウト、監視、トラブルシューティング
圧縮は簡単にデプロイできますが、間違えると簡単に壊れます。運用機能として段階的に展開し、影響を測定し、ロールバックを容易にしておいてください。
安全なロールアウト計画
- カナリアで始め、少量のトラフィックまたは内部クライアントだけに新しい
Content-Encoding(例:zstd)を返す - 段階的に比率を増やす(1% → 5% → 25% → 50% → 100%)
簡単にロールバックできる手段を用意します:
- ゲートウェイ/サービス側のフラグで圧縮を無効化(または
gzipにフォールバック) - 特定のエンドポイントを除外(ファイルダウンロード、既に圧縮されたメディアなど)
- 設定変更だけで済むようにし、コードデプロイを避ける
監視すべき項目(とその理由)
- CPU(サーバー/可能ならクライアント): 高い圧縮レベルでCPUがスパイクする
- レイテンシのパーセンタイル(p50/p95/p99): 平均は改善しても尾部が悪化することがある
- レスポンスサイズ: エンドポイントごとのワイヤ上のバイト数、圧縮有無の差
- エラー率: 4xx/5xx、クライアントのデコードエラー、タイムアウト
トラブルシューティングチェックリスト
よくある原因:
- 二重圧縮: 上流が圧縮しておりゲートウェイも圧縮している
- ヘッダーの不一致:
Content-Encodingがあるがボディが圧縮されていない(またはその逆) - ネゴシエーションの失敗:
Accept-Encodingを無視している/対応していないエンコーディングを返している - ストリーム破損: ボディの切断、誤った
Content-Length、プロキシ/CDNによる破壊
デバッグ時は生のヘッダー/ボディを取得して既知のツールで復号できるか確認してください。
クライアント期待値のドキュメント化
サポートするエンコーディングをドキュメントで明記し、例を示してください:
- クライアントが送るべきもの:
Accept-Encoding: zstd, br, gzip - 受け取る可能性のあるもの:
Content-Encoding: zstd(またはフォールバック)
SDKを配布しているなら、小さなコピペ可能な復号例と、BrotliやZstandardをサポートする最小バージョンを明記してください。
よくある質問
APIのレスポンス圧縮はいつ有効にすべきですか?
レスポンスがテキスト中心(JSON/GraphQL/XML/HTML)で、中〜大サイズであり、ユーザーが遅い/高コストのネットワークを使っている、あるいはあなたが送信データ量に対して課金されている場合に有効です。小さすぎるレスポンス、すでに圧縮されているメディア(JPEG/MP4/ZIP/PDF)や、追加の処理がp95/p99レイテンシを悪化させるCPUがボトルネックのサービスではスキップするか、高い閾値を使ってください。
レスポンスが小さくなっても、なぜAPIが遅くなることがあるのですか?
圧縮は帯域をCPU(と場合によってはメモリ)に交換します。圧縮処理にかかる時間がサーバーが最初のバイトを送れる時点(TTFB)を遅らせるため、特に高帯域・低遅延の接続ではレスポンスが小さくなっても全体では遅くなることがあります。負荷時にはキューイングが発生して尾部レイテンシ(p95/p99)が悪化することがよくあるため、バイト数だけで判断せず、エンドツーエンドの時間で評価してください。
ZSTD、Brotli、GZIPのどれを選べばよいですか?
多くのAPIで実用的な優先順位は次の通りです:
zstdを最優先(高速で良好な比率)- 次に
br(テキストで最小になりやすいがCPUコストが高い場合あり) - 最後に
gzip(互換性が最も広い)
最終的にはクライアントが Accept-Encoding で何を送ってくるかに基づいて選び、常に安全なフォールバック(通常は gzip や identity)を用意してください。
動的なAPIレスポンス向けにどの圧縮レベルが妥当ですか?
まずは低めで測定することを推奨します。
- ZSTD: 多くの動的JSON APIではレベル 1–3(必要に応じて 3–5)
- Brotli: ランタイム圧縮は 1–4、事前圧縮/静的配信では 8–11 を検討
- GZIP: 良いデフォルトは 5–6
高いレベルはわずかなサイズ改善のためにCPUを大きく消費し、p95/p99を悪化させることが多いので注意してください。
すべてのレスポンスを圧縮すべきですか、それともサイズに基づいてのみですか?
最小サイズの閾値を設定して、小さいペイロードでCPUを浪費しないようにします。
- 一般的な開始点: 1–2 KB未満は圧縮しない
- CPU負荷が高い、あるいはチャッティなAPIなら 4 KB を検討
エンドポイントごとにバイト削減量、追加されたサーバー処理時間、p50/p95/p99への影響を比べてチューニングしてください。
どのペイロードタイプがよく圧縮され、どれが圧縮に向かないですか?
構造化され繰り返しが多いコンテンツはよく縮みます:
- 優秀: JSON, GraphQL, XML, HTML, 大きなテキストログ
- 「場合による」: Protobuf/MessagePack(多くは圧縮可能。実測が必要)
- 通常圧縮の恩恵が少ない: JPEG/PNG/WebP, MP4, ZIP/gz, 多くの PDF
一般的にはテキスト系の Content-Type にのみ圧縮を有効にし、既に圧縮されている形式は無効にするのが簡単で安全です。
Accept-Encoding と Content-Encoding はAPIでどう機能しますか?
HTTPの交渉に従ってください:
- クライアントが
Accept-Encodingを送る(例:zstd, br, gzip) - サーバーは対応する
Content-Encodingを返す
クライアントが Accept-Encoding を送らなければ、通常は圧縮しないのが最も安全です。クライアントが広告していない Content-Encoding を返すとデコードに失敗する恐れがあります。
圧縮を使うとき、なぜ Vary: Accept-Encoding が重要ですか?
必ず応答に次を含めてください:
Vary: Accept-Encoding
これがないと CDN やプロキシがあるエンコーディング(例: gzip)をキャッシュしてしまい、そのキャッシュをデコードできないクライアントに誤って返してしまうことがあります。複数のエンコーディングをサポートする場合、このヘッダーは必須です。
本番でよく見られる圧縮バグは何ですか?
よくある失敗モードは以下です:
- 二重圧縮(オリジンが圧縮し、ゲートウェイ/CDNがさらに圧縮)
- ヘッダーとボディの不一致(
Content-Encodingが設定されているが実際は圧縮されていない) - 交渉ミス(
Accept-Encodingを無視して返す) - プロキシ/CDNの干渉(ヘッダーを削除または改変)
- ストリーミング時の誤った
Content-Length
デバッグ時は生のレスポンスヘッダーをキャプチャして、既知のツールでデコードができるかを確認してください。
API圧縮を安全にロールアウトし、監視するにはどうすればよいですか?
パフォーマンス機能として段階的にロールアウトしてください:
- Canary(小さなトラフィック)から始め、段階的に増やす(1% → 5% → 25% → 50% → 100%)
- 迅速にロールバックできる機構(フラグやゲートウェイ設定)を用意
- 監視すべき指標:
- サーバーのCPU使用率/飽和度
- p50/p95/p99 レイテンシ と TTFB
- ワイヤ上のバイト数(圧縮前後)
- エラー/タイムアウト とクライアントのデコード失敗
負荷時に尾部レイテンシが上がるなら、レベルを下げる、閾値を上げる、あるいはより高速なコーデック(多くの場合 ZSTD)に切り替えてください。