GCP Cloud CDNの「キャッシュ制御」を極める:HTTPヘッダーと仲良くなるための実務ガイド
こんにちは。現場でネットワークトラブルに頭を抱えるエンジニアの皆さん、あるいはこれからインフラ設計を本格化させようとしている皆さん。
今日は、Google Cloudの「Cloud CDN」について、少し深い話をしようと思います。教科書には「Cloud CDNを使えば高速化できる」と書いてありますが、実際に運用すると必ず突き当たる壁があります。「なぜかキャッシュされない」「古いコンテンツが消えない」「Varyヘッダーでキャッシュが爆発した」。これらは全て、HTTPヘッダーの解釈をわずかに読み違えていることが原因です。
今回は、RFCの仕様という「聖典」をベースにしつつ、現場で確実に効く「キャッシュ戦略の勘所」を解説します。
—
1. キャッシュの司令塔:Cache-Controlヘッダーの現場的解釈
Cloud CDNが「このリソースをどれくらいの期間、どこに保存するか」を判断するのは、オリジンサーバーから送られてくる Cache-Control ヘッダーです。ここを制する者がCDNを制します。
主要パラメーターの「現場的な捉え方」
public: キャッシュ可能であることを明示します。CDNでキャッシュさせたいなら必須です。private: CDNや共有キャッシュでの保存を禁じます。ブラウザのみでキャッシュさせたい個人情報を含むAPIレスポンスなどで使います。max-age=<seconds>: ブラウザ(クライアント)のキャッシュ有効期限です。s-maxage=<seconds>: ここが最重要。 CDN(共有キャッシュ)専用の有効期限です。もしCDNにキャッシュさせたいなら、max-ageよりもこちらを優先的に設定すべきです。
実務Tips:
「ブラウザにはキャッシュさせたくないが、CDNにはキャッシュさせたい」というケースは意外と多いです。その場合は Cache-Control: public, s-maxage=3600, max-age=0 と指定します。これでCDNは1時間キャッシュしつつ、ブラウザは常に再検証を行うようになります。
—
2. Varyヘッダーという「諸刃の剣」
Vary ヘッダーは、特定のHTTPリクエストヘッダーの値に基づいてキャッシュを「出し分ける」ために使います。例えば Vary: Accept-Encoding とすれば、Gzip圧縮対応のブラウザとそうでないブラウザでキャッシュを別々に保持できます。
しかし、ここでエンジニアが陥りやすい罠があります。
警告: Vary: User-Agent は絶対に避けてください。
スマホ、タブレット、PC、ブラウザのバージョンごとにキャッシュが作られ、キャッシュヒット率が劇的に低下する「キャッシュ・フラグメンテーション(キャッシュの断片化)」を引き起こします。
—
3. 実践:ヘッダーの検証とデバッグ
では、実際に自分の設定が正しく動作しているか確認しましょう。インフラエンジニアの相棒 curl を使います。
# -I オプションでヘッダーのみを取得
# CDN経由のレスポンスを確認する
curl -I -H "Host: example.com" https://<ロードバランサーのIP>/api/v1/resource
返ってきたレスポンスに以下のヘッダーが含まれているかを確認してください。
Age: キャッシュに保存されてから何秒経過したか(ここが0ならミスです)Via: 経由したキャッシュサーバーの情報(GoogleとあればCDNが反応しています)X-Cache:HITとなっていれば成功です。
—
4. プログラミング言語での実装例(Python)
APIサーバーをPythonで書いている場合、以下のようにレスポンスヘッダーを制御するのが定石です。
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/api/data')
def get_data():
response = make_response("キャッシュされるべきデータ")
# CDNには1時間、ブラウザにはキャッシュさせない設定
response.headers['Cache-Control'] = 'public, s-maxage=3600, max-age=0'
# 圧縮対応をCDNに伝える
response.headers['Vary'] = 'Accept-Encoding'
return response
—
5. 最後に:障害を未然に防ぐために
Cloud CDNのキャッシュ設定を更新した直後、Cache-Control の変更が反映されるまでには、CDNのエッジロケーションでの伝搬時間(数十秒〜数分)がかかります。
もし「間違えてキャッシュさせてしまった!」という場合は、焦ってオリジンをいじるのではなく、GCPコンソールまたは gcloud コマンドで「キャッシュの無効化(Invalidation)」を実行してください。
# 全てのパスのキャッシュを無効化する場合
gcloud compute url-maps invalidate-cdn-contents <ロードバランサー名> --path "/*"
ネットワークエンジニアの仕事は、通信の「道」を作ることだけではありません。その道を通るデータが、いつ、どこで、どのように振る舞うかをコントロールすることこそが、真の価値です。
皆さんのサービスが、今日の知識でより速く、より安定したものになることを願っています。何か詰まったら、まずは curl -v でヘッダーを覗くこと。これだけは忘れないでくださいね。
コメント