
CDNキャッシュ向けレスポンスヘッダーCache-Control:s-maxage を触ってみた
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
CDNやプロキシといった共有キャッシュ向けにキャッシュの保持期間を制御する Cache-Control: s-maxage=seconds というレスポンスヘッダーが存在します。
ブラウザとCDNでキャッシュの保持期間を分けたい時や、マルチCDNの構成においてオリジン側でCDNのキャッシュの保持期間を一元管理したい時などに重宝します。
本記事では、この共有キャッシュ向けレスポンスヘッダーについて、かんたんに紹介します。
ブラウザ向けの max-ageと共有キャッシュ向けの s-max-age
s-maxage によく似たディレクティブに max-age があります。どちらも Cache-Control と一緒に用いますが、用途は少し異なります。
max-age はCDNやプロキシといった共有キャッシュ、及び、クライアント向けのキャッシュ設定です。
s-maxage は共有キャッシュに特化したキャッシュ設定であり、max-age / Expires よりも優先されます(上書きます)。その上で、CDN によって、CDN設定とs-maxage のどちらのキャッシュ時間を優先するか決まります。
s-maxage の綴りは s-max-age ではないので、ご注意ください。
CloudFront と Cache-Control:max-age, s-maxage の連携
CDN に Amazon CloudFront を用いているケースにおいて、max-age と s-maxage の値によって CDN(エッジ)ではどのようにキャッシュされるのでしょうか。
CloudFrontのキャッシュポリシーにデフォルトの Managed-CachingOptimized を設定している場合で確認します。
このポリシーは次の通りです。
- Minimum TTL : 1
- Maximum TTL : 31536000
- Default TTL : 86400
※ Minimum TTL=0 の場合、下記ルールとは異なります。詳細はドキュメントを参照してください。
max-ageもs-maxageも未設定の場合
オリジンが max-age も s-maxage も返さない場合、
- CloudFront は Default TTL の期間だけキャッシュ保持(厳密には MinimumとDefaultの大きい方)
- クライアントのキャッシュ期間はブラウザ依存
max-ageは設定されていてs-maxageは未設定の場合
オリジンが max-age を返し s-maxage は返さない場合、
- CloudFront は Minimum TTL/Maximum TTL/
max-ageの中から、2番めに大きい値だけキャッシュ。例えば Minimum <max-age< Maximum の場合、max-ageの期間だけキャッシュ - クライアントは
max-ageの期間だけキャッシュ
max-ageとs-maxageの両方が設定されている場合
オリジンが max-age とs-maxage の両方を返す場合、
- CloudFront は
max-ageよりもs-maxageを優先し、Minimum TTL/Maximum TTL/s-maxageの中から、2番めに大きい値だけキャッシュ。例えば Minimum <s-maxage< Maximum の場合、s-maxageの期間だけキャッシュ - クライアントは
max-ageの期間だけキャッシュ
S3 がオリジンの場合に s-maxage を確認
CloudFront のオリジンに S3 を設定し、s-maxage の挙動を確認します。
CloudFront のキャッシュポリシーを Managed-CachingOptimized に設定し、S3オブジェクトのメタデータで Cache-Control を設定します。
Cache-Control: s-maxage=300,max-age=180 の場合、 Minimum TTL(=1) < s-maxage(=300) < Maximum TTL(= 31536000) のため、エッジでは s-maxage で指定した秒数だけキャッシュされるはずです。
初回アクセス時
初回アクセス時には キャッシュミスします。
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 14 Connection: keep-alive Date: Wed, 20 Jan 2021 15:29:10 GMT Last-Modified: Wed, 20 Jan 2021 15:09:33 GMT ETag: "910c8bc73110b0cd1bc5d2bcae782511" Cache-Control: s-maxage=300,max-age=180 Accept-Ranges: bytes Server: AmazonS3 X-Cache: Miss from cloudfront ...
キャッシュ期間内の2度目のアクセス
290秒後にアクセスします(max-age < 290 < s-maxage)。
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 14 Connection: keep-alive Date: Wed, 20 Jan 2021 15:29:10 GMT Last-Modified: Wed, 20 Jan 2021 15:09:33 GMT ETag: "910c8bc73110b0cd1bc5d2bcae782511" Cache-Control: s-maxage=300,max-age=180 Accept-Ranges: bytes Server: AmazonS3 X-Cache: Hit from cloudfront Via: 1.1 53767392640cf5282c1ce18d7cc7b0e1.cloudfront.net (CloudFront) X-Amz-Cf-Pop: HAM50-C1 X-Amz-Cf-Id: r4CPRg6eZDjv25BWIjwjYvbvkwCMNJRhQYB33AAoWLMy4MTKMzVO4g== Age: 290
CloudFront では s-maxage の時間だけキャッシュされているので、キャッシュヒットします。
エッジキャッシュのstale後のアクセス
エッジキャッシュが stale になったあとにアクセスします。
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 14 Connection: keep-alive Last-Modified: Wed, 20 Jan 2021 15:09:33 GMT Accept-Ranges: bytes Server: AmazonS3 Date: Wed, 20 Jan 2021 15:34:10 GMT Cache-Control: s-maxage=300,max-age=180 ETag: "910c8bc73110b0cd1bc5d2bcae782511" X-Cache: RefreshHit from cloudfront ...
X-Cache: RefreshHit from cloudfront から、エッジキャッシュが stale なので、オリジンにアクセスしていることがわかります。
オリジンS3バケットのサーバーアクセスロギングから対応するログを確認すると、この RefreshHit のリクエスト(conditional GET)に対して 304: Not Modified を返していました。
008600d... BUCKET-NAME [20/Jan/2021:15:34:09 +0000] 130.***.***.*** - ERXXX REST.GET.OBJECT s-maxage.html "GET /s-maxage.html HTTP/1.1" 304 - - 14 9 - "-" "curl/7.64.1" - Ng...= - - - BUCKET-NAME.s3.amazonaws.com -
s-maxageとSurrogate-Control ヘッダーとの違いは?
Cache-Control: s-maxage ディレクティブと同様の機能を一部のCDNベンダーは Surrogate-Control ヘッダーで提供しています。
Surrogate-Control は Cache-Control の エッジ版であり、W3C の 2001年版の Edge Architecture Specificationにも確認できます。
実際の仕様はベンダー・ミドルウェアによって細部が異なります。
例えばFastly の場合、エッジキャッシュの保持期間に関してCache-Control: s-maxage=3600とSurrogate-Control: max-age=3600は同じであり、Surrogate-Controlヘッダーはオリジン-CDN間でのみ利用され、クライアント向けレスポンスからは除外される点がCache-Controlと異なります。
参考 : Configuring caching | Fastly Help Guides
Surrogate-Control のCDN向け 統一規格 CDN-Cache-Control レスポンスヘッダー のドラフトが公開中
CDN に特化した統一的なキャッシュヘッダーがほしいということで、CDN-Cache-Control という新しいレスポンスヘッダーのドラフトが 2020年11月に公開されました。
The CDN-Cache-Control HTTP Response Header Field
Cache-Control の仕様はすでに十分すぎるくらいに複雑で拡張が難しく、CDNだけでなくプロキシも含めた共有キャッシュが対象であること、Surrogate-Control はベンダーごとに独自仕様となっていて、互換性を維持したまま拡張するのが難しいことから、新しいヘッダーを用意することになったようです。
マルチCDN環境でCDNのキャッシュ設定を一元管理できる未来を期待したい一方で、ドラフトによると "Individual CDNs can choose to define their own control mechanisms that take precedence over this header field."とあるので、厳しい現実を突きつけられる可能性もあります。
このドラフトの著者は Akamai/Fastly/Cloudflare の CDN ベンダーから構成されています。
著者の一人 Mark Nottingham さんは Surrogate-Control を定義した W3C Note 04 August 2001 版 Edge Architecture Specification の著者の一人でもあります。
まとめ
CDNのキャッシュを制御するには、CDN本体の設定だけでなく、オリジンのレスポンスヘッダー(Cache-Control: s-maxage/Surrogate-Control)でも制御できます。
設定が分散していると挙動を把握するのが難しくなるため、まずは CDN 単体でキャッシュ設定することをおすすめします。
最大の疑問点、s-maxageの綴りがs-max-ageでない理由については、最後までわかりませんでした。
それでは。
参考
- Cache-Control - HTTP | MDN
- Managing how long content stays in the cache (expiration) - Amazon CloudFront
- Request and Response Behavior for Amazon S3 Origins - Amazon CloudFront
- CDNのキャッシュを制御する CDN-Cache-Control ヘッダ - ASnoKaze blog
- IETF Draft : The CDN-Cache-Control HTTP Response Header Field
- W3C : Edge Architecture Specification 1.0
- Content delivery networks (CDNs) - web.dev
- Controlling caching | Fastly Help Guides
- 渋川 よしき 『Real World HTTP 第2版』 13.4節 CDN(Content Delivery Network)













