キャッシュの「神」を味方につける:Varyヘッダーと運用のリアル
ネットワークエンジニアとして現場を渡り歩いていると、「キャッシュが効かない」「スマホで見ると表示が崩れる」という相談を数え切れないほど受けてきました。その原因の多くは、HTTPの地味な、しかし極めて強力なヘッダー――`Vary`――の理解不足にあります。
今日は、RFC 7231に定義されたこの「キャッシュの交通整理係」について、教科書的な説明はすっ飛ばして、現場の血肉となる知識を共有しましょう。
—
1. なぜ「Vary」が必要なのか?
Webのキャッシュは単純な世界です。ブラウザやCDNは、基本的には「URL」をキーにしてリソースをキャッシュします。しかし、現実はそう単純ではありません。
同じURLでも、クライアントが「圧縮に対応しているか(`Accept-Encoding`)」や「スマホかPCか(`User-Agent`)」によって、返すべきコンテンツは変わります。もしCDNがこの出し分けを無視して、PC用のキャッシュをスマホに送りつけたら?あるいはその逆が起きたら?
ここで登場するのが `Vary` ヘッダーです。これはオリジンサーバーからキャッシュサーバーに対し、「このレスポンスは、リクエストに含まれる『このヘッダーの値』をキーの一部として管理しろ」と命じるタグなのです。
—
2. 通信フロー:パケットの視点
クライアントが `Accept-Encoding: gzip` を付けてリクエストを送ると、サーバーは `Vary: Accept-Encoding` と共にgzip圧縮されたデータを返します。
クライアント -> [GET /api/data] -> CDN
CDN (キャッシュなし) -> [GET /api/data, Accept-Encoding: gzip] -> オリジン
オリジン -> [200 OK, Content-Encoding: gzip, Vary: Accept-Encoding] -> CDN
CDN -> [保存: URL + gzip版] -> クライアント
次に別のクライアントが `Accept-Encoding: identity`(圧縮なし)でリクエストすると、CDNは「キャッシュはあるが、Varyで指定されたヘッダーが異なる」と判断し、再度オリジンへ取りに行きます。これが正しい挙動です。
—
3. 実務で遭遇する「Varyの罠」とキャッシュヒット率
ここでシニアエンジニアからの警告です。`Vary` は便利ですが、安易に `Vary: User-Agent` を指定してはいけません。
`User-Agent` は数千種類存在します。これをキャッシュキーに含めると、キャッシュのバリエーションが爆発し、キャッシュヒット率は限りなくゼロに近づきます。これが「キャッシュが効かない」と悩む現場の典型的な敗因です。
ベストプラクティス
- `Vary: Accept-Encoding` は必須。現代のWebでは標準的です。
- `User-Agent` での出し分けは、可能な限り避ける。やるなら「PC/スマホ」などの大まかな分類をサーバー側で判定し、`X-Device-Type` のようなカスタムヘッダーを `Vary` に入れるのが筋です。
—
4. 検証とデバッグ:今日から使えるコマンド
現場で「本当にキャッシュが効いているか?Varyはどうなっているか?」を確認するには `curl` が一番です。
ヘッダー情報を確認する(-Iオプション)
curl -I -H “Accept-Encoding: gzip” https://api.example.com/data
出力結果の確認
HTTP/1.1 200 OK
Content-Encoding: gzip
Vary: Accept-Encoding <-- これが入っていればキャッシュサーバーは正しく処理する
X-Cache: HIT <-- CDNのヒット状況も要チェック
もしPythonでAPIクライアントを書いているなら、Varyの挙動を意識してヘッダーを制御する必要があります。
import requests
url = "https://api.example.com/data"
Varyを考慮して、適切なAccept-Encodingを送る
headers = {"Accept-Encoding": "gzip, deflate"}
response = requests.get(url, headers=headers)
レスポンスヘッダーを確認して、サーバーがVaryを正しく返しているかデバッグ
print(f"Varyヘッダー: {response.headers.get('Vary')}")
---
5. Nginxでの設定例
インフラ屋として、Nginxでレスポンスに `Vary` を付与する設定も記載しておきます。基本は `gzip` モジュールが自動で行いますが、明示的に制御したい場合は以下のように記述します。
location /api/ {
# 圧縮を有効化
gzip on;
gzip_types application/json;
# Varyヘッダーを付与してキャッシュ効率を最適化
# 既にgzipモジュールが自動で Vary: Accept-Encoding を付与してくれますが、
# 独自キャッシュを組む場合は以下のように追加することも可能です
add_header Vary “Accept-Encoding, Authorization”;
}
—
最後に:ネットワークを俯瞰する視点
`Vary` を使いこなすということは、「クライアント・CDN・オリジンという3者間の合意形成を制御する」ということです。
設定一つでパフォーマンスが劇的に変わるのがWebインフラの醍醐味ですが、やりすぎれば複雑性を招き、障害の温床になります。「本当にそのヘッダーによる出し分けが必要か?」と常に自問自答してください。
何かあれば、またいつでも質問してください。現場で培った知見を、惜しみなく共有しますよ。
コメント