なぜ「エラー」をキャッシュするのか?――GCP Cloud CDNで学ぶネガティブキャッシュの極意
こんにちは。現場で叩き上げのSREをしています。
クラウドインフラを運用していると、避けて通れないのが「オリジンへの負荷」です。特に、存在しないリソースへの執拗なアクセスや、一時的な障害時に発生するエラーレスポンスが、バックエンドのデータベースやアプリケーションサーバーを直撃し、二次障害を引き起こす光景を何度も見てきました。
そんな時、我々エンジニアの強力な武器になるのが「ネガティブキャッシュ(Negative Caching)」です。今日は、GCP Cloud CDNにおけるこの機能を深掘りし、実務でどのように活用し、何を注意すべきか、現場の視点で解説します。
—
1. ネガティブキャッシュが解決する「負の連鎖」
通常、CDNは「成功したレスポンス(200 OKなど)」をキャッシュしますが、ネガティブキャッシュは「失敗したレスポンス(404 Not Found や 502 Bad Gateway など)」をあえて一定時間保持します。
なぜこれが必要か? 例えば、攻撃者や誤設定されたクライアントが、存在しないURL(/non-existent-resource)を毎秒数万回リクエストしてきたとします。もしネガティブキャッシュがない場合、そのリクエストはすべてオリジンに到達し、オリジンの CPU や DB のコネクションを食いつぶします。
ネガティブキャッシュを有効にすることで、最初のエラーレスポンスをエッジサーバーが「覚えて」おき、次回以降のリクエストはオリジンに飛ばさずエッジで即座に遮断(あるいはエラーを返却)できるのです。
—
2. 通信フロー:パケットはどこで止まるのか
ネガティブキャッシュが有効な場合、通信のシーケンスは以下のようになります。
1. クライアントがリクエストを送出。
2. エッジサーバーがキャッシュを検索し、ヒットしなければオリジンへ転送。
3. オリジンが 404 Not Found を返却。
4. エッジサーバーがそのステータスと Cache-Control ヘッダーを解析し、一定期間(TTL)キャッシュとして保存。
5. 次回以降のリクエストに対しては、オリジンを叩かずエッジが 404 を即座に応答。
この「オリジンを叩かない」という一点が、大規模トラフィック下では命綱になります。
—
3. GCP Cloud CDNでの設定とパラメータ
GCPでこれを制御するのは、主にバックエンドサービスの negativeCachingPolicy という設定です。
設定の勘所
code: キャッシュ対象とするHTTPステータスコード(404, 502, 503, 504など)。ttl: エラーをキャッシュする秒数。短すぎると負荷軽減にならず、長すぎると復旧後の追従が遅れます。
以下は、gcloud コマンドで設定を適用する例です。
# 対象のバックエンドサービスに対してネガティブキャッシュポリシーを適用
gcloud compute backend-services update [YOUR_BACKEND_SERVICE_NAME] \
--global \
--negative-caching \
--negative-caching-policy="404=300,502=60"
# 404は300秒(5分)、502は60秒キャッシュする設定
—
4. 実務上の注意点:キャッシュの罠
ネガティブキャッシュは諸刃の剣です。以下の点には細心の注意を払ってください。
① 502/503/504 の扱い
404 をキャッシュするのは安全ですが、502 Bad Gateway や 503 Service Unavailable を長時間キャッシュするのは危険です。オリジンが復旧した瞬間に、エッジのキャッシュが消えるまで「ずっとエラーが続く」という悲劇を招きます。これらは短めの TTL に設定するのが鉄則です。
② ヘッダーの確認
Cloud CDN がエラーをキャッシュするかどうかは、オリジンが返す Cache-Control ヘッダーにも依存します。もしオリジンが Cache-Control: private や no-store を返していれば、設定に関わらずキャッシュされません。
以下は、オリジン側で適切に制御するためのPython(Flask)のサンプルです。
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/test-error')
def error_route():
# 意図的にエラーを返しつつ、CDNにキャッシュさせるためのヘッダーを付与
response = make_response("Not Found", 404)
response.headers['Cache-Control'] = 'public, max-age=300'
return response
—
5. デバッグのTips:正しくキャッシュされているか?
「設定したはずなのに効いていない」という時、私は必ず curl で Via ヘッダーと Age ヘッダーを確認します。
# -Iでヘッダーのみ取得
curl -I https://your-site.com/non-existent-resource
期待通りの挙動であれば、レスポンスヘッダーに以下が含まれます。
X-Cache: HIT(キャッシュから返却されている)Age: [秒数](キャッシュされてからの経過時間)
もし X-Cache: MISS が続くようなら、オリジンの Cache-Control ヘッダーが邪魔をしていないか、あるいは GCP のコンソール上で「キャッシュキーの構成」が意図した通りになっているかを確認してください。
—
まとめ
ネガティブキャッシュは、単なる「エラーの記憶」ではなく、「オリジンを守るための防波堤」です。
1. 404 は長めにキャッシュしても安全(リソースが復活する頻度は低いため)。
2. 5xx系 は慎重に。復旧を阻害しないよう極短時間に設定。
3. ヘッダーの確認 を怠らない。
この機能を使いこなせれば、トラフィックのスパイクが起きても、肩の力を抜いてコーヒーを飲んでいる余裕が生まれます。皆さんのインフラが、より堅牢なものになることを願っています。
それでは、また現場でお会いしましょう。
コメント