CloudflareがCDN向けキャッシュヘッダーCDN-Cache-Controlを実装したので触ってみた

CDNキャッシュ向けのHTTPレスポンスヘッダーCDN-Cache-ControlをCloudflareがサポートしました
2021.05.24

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

本エントリで紹介している"Targeted HTTP Response Header Fields for Cache Control" は RFC 9213: Targeted HTTP Cache Control として2022年6月に公開されました。

昨年から特定用途に特化したキャッシュを制御するHTTPレスポンスヘッダーの仕様がAkamai/Cloudflare/Fastlyから共同提案されています。

共著者の一社であるCloudflareがCDN向けのCDN-Cache-Controlを早速正式リリースしたため、触ってみました。

CDN-Cache-Control はどういうキャッシュ?

Webコンテンツの配信を最適化するために、HTTPレスポンスヘッダーを利用したキャッシュ機能がよく使われ、 プロキシサーバー、CDN、ブラウザなど様々なコンポーネントで可能です。

例えば

Cache-Control: max-age=60, s-maxage=120

というレスポンスを返すと、ブラウザでは60秒キャッシュされ、プロキシ、CDN 向けでは 120 秒キャッシュされます。

とはいえ、より細かい粒度でキャッシュ設定したいことがあります。

その要望に答えるのが本提案であり、キャッシュの用途別のレスポンスヘッダーを定義しています。 その第1段が CDNキャッシュに特化した CDN-Cache-Control フィールドです。

This specification defines a convention for HTTP response header fields that allow directives controlling caching to be targeted at specific caches or classes of caches. It also defines one such header field, targeted at Content Delivery Network (CDN) caches.

https://www.ietf.org/archive/id/draft-cdn-control-header-01.html#name-cache-behavior

Cloudflare は他社に先駆けて、この機能をリリースしました。

CDN-Cache-Control を使うと、

  1. プロキシとCDNでキャッシュ設定を分ける
  2. 多段CDN構成でCDN全体で一貫した同じキャッシュ設定を用いる
  3. 多段CDN構成でデフォルトのキャッシュ設定を定義しつつ、特定のCDNだけ別設定を定義
  4. マルチCDN構成でCDNキャッシュ設定をオリジンに寄せる

といったことが可能になります。

この動作を確認します。

キャッシュの優先準備

CDNのキャッシュ設定は様々な方法があります。

優先順位は高いものから順に以下の通りです。

  1. (CDN側)Edge Cache TTL Page Rule
  2. (オリジン側)Cloudflare-CDN-Cache-Control ※ Cloudflare CDN固有のキャッシュ設定
  3. (オリジン側)CDN-Cache-Control ※ CDN汎用のキャッシュ設定
  4. (オリジン側)Cache-Control:s-max-age
  5. (CDN側)Cloudflare デフォルト

プロキシとCDNでキャッシュ設定を分ける

一番基本的な使い方です。

Cache-Controlのs-maxageの設定は、共有キャッシュ全体で適用されます。

共有キャッシュをCDN系とその他(プロキシ)で分けたい場合、次の通り設定します。

Cache-Control: max-age=60, s-maxage=120
CDN-Cache-Control: max-age=600

リクエストします。

HTTP/1.1 200 OK
Date: Sun, 23 May 2021 22:38:14 GMT
Content-Type: image/png
Content-Length: 368
Connection: keep-alive
Last-Modified: Sat, 22 May 2021 11:53:42 GMT
ETag: "60a8f0c6-170"
Cache-Control: max-age=60, s-maxage=120
CDN-Cache-Control: max-age=600
CF-Cache-Status: MISS
Accept-Ranges: bytes
cf-request-id: 0a3cfa10cd0000416ee095a000000001
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report?s=M...M"}],"group":"cf-nel","max_age":604800}
NEL: {"report_to":"cf-nel","max_age":604800}
Server: cloudflare
CF-RAY: 6541c5faeb7a416e-HAM

CDN がキャッシュ後 CDN-Cache-Control: max-age 内であれば、 CDN キャッシュにヒットします。

...
CF-Cache-Status: HIT
Age: 82
...

CDN-Cache-Control: max-age を超えると、オリジンに条件付きリクエストをします。 その時の CF-Cache-StatusREVALIDATED です。

...
CF-Cache-Status: REVALIDATED
...

CDN-Cache-Control は以下のディレクティブに対応しています。

  • max-age
  • must-revalidate
  • no-store
  • no-cache
  • private

多段CDN構成でCDN全体で一貫した同じキャッシュ設定を用いる

オリジンとブラウザの間に複数のCDNを挟む多段CDN構成が採用されることがあります。

そのような構成において、各 CDN のキャッシュ設定を統一させたい場合、CDN-Cache-Control を活用できます。

Cache-Control: max-age=60, s-maxage=120
CDN-Cache-Control: max-age=600

CDN-Cache-Control ヘッダーはダウンストリーム(ブラウザ寄り)にも渡されるので、 ダウンストリームにいる CDN が CDN-Cache-Control をサポートする場合、そのCDNにも同じキャッシュ設定が適用されます。

現時点では CDN-Cache-Control をサポートする CDN は Cloudflare だけのため、将来に期待しましょう。

多段CDN構成でデフォルトのキャッシュ設定を定義しつつ、特定のCDNだけ別設定を定義

オリジンとブラウザの間に複数のCDNを挟む多段CDN構成が採用されることがあります。

そのような構成において、CDN全体でデフォルトのキャッシュ設定を定義しつつ、特定のCDNだけキャッシュ設定を分けたい場合、CDN-Cache-ControlCloudflare-CDN-Cache-Controlと組み合わせて活用します。

Cloudflare-CDN-Cache-Control は Cloudflare CDN に特化したキャッシュ用レスポンスフィールドです。

Cache-Control: max-age=60, s-maxage=120
CDN-Cache-Control: max-age=600
Cloudflare-CDN-Cache-Control: max-age=180

Cloudflare CDNでは Cloudflare-Cache-Control は s-max-age や CDN-Cache-Control よりも優先して評価されます。 また、Cloudflare-CDN-Cache-Control ヘッダーは Cloudflare CDNでしか処理されないため、Cloudflare CDNのダウンストリームにはこのヘッダーを返しません。

HTTP/1.1 200 OK
...
Cache-Control: max-age=60, s-maxage=120
CDN-Cache-Control: max-age=600
CF-Cache-Status: MISS
...

なお、CDN 汎用的なヘッダー CDN-Cache-ControlとCDNベンダー固有のヘッダー(上記例では Cloudflare-CDN-Cache-Control)間では、先頭のものほど優先される target list として管理されます。

[ExampleCDN-Cache-Control, CDN-Cache-Control]

このリストは、実装により、固定、ユーザーがカスタマイズ可能、あるいはリクエストごとにカスタマイズ可能となるようです。

2.1. Cache Behavior

A cache that implement this specification has a target list - an ordered list of the targeted field names that it uses for caching policy, with the order reflecting priority from most applicable to least. The target list might be fixed, user-configurable, or generated per request, depending upon the implementation.

https://www.ietf.org/archive/id/draft-cdn-control-header-01.html#name-cache-behavior

マルチCDN構成でCDNキャッシュ設定をオリジンに寄せる

エリアや CDN のサービス稼働状況によって CDN を使い分ける マルチ CDN 構成が採用されることがあります。

そのような構成において、CDN のキャッシュ保持期間設定をオリジンサーバーで一元管理したい場合、CDN-Cache-Control を活用できます。

Cloudflare Edge Cache TTL Page Rule は最優先される

Cloudflare ではオリジンのキャッシュヘッダーとは別に、Cloudflare CDN の設定画面でエッジの TTL を設定できます。

ルールが存在する場合、Cloudflare-CDN-Cache-Control/CDN-Cache-Control よりも優先されます。

Edge Cache TTL Page Rule で2時間キャッシュするよう設定します。

この状態でのレスポンスの抜粋です。

...
Cache-Control: max-age=60, s-maxage=120
CDN-Cache-Control: max-age=600
CF-Cache-Status: HIT
Age: 3120
...

エッジキャッシュは CDN-Cache-Controlのmax-age=600よりも経過しているにも関わらず(Age=3120)、キャッシュ・ヒットしています。

Edge Cache TTL Page Rule の設定が Cloudflare-CDN-Cache-Control/CDN-Cache-Control よりも優先されていることがわかります。

フォールバックは Cloudflare デフォルトの TTL

Cloudflare CDN は HTTP ステータスごとにデフォルトのキャッシュ時間が設定されています。 例えば、200 ステータスは 120分キャッシュされます。

  • Cloudflare-CDN-Cache-Control
  • CDN-Cache-Control
  • Cache-Control(s-max-age)

いずれも存在しない場合、このデフォルト TTL が適用されます。

最後に

CDNキャッシュ向けのHTTPレスポンスヘッダー CDN-Cache-Controlの仕様がAkamai・Cloudflare・Fastlyの3社から提案されており、 Cloudflare が提案中の仕様を早速サービス提供しました。

本機能を使うと

  • 共有キャッシュの設定をCDNとその他で分ける
  • 複数のCDNのキャッシュ設定を一元管理する

といったことを、オリジンのレスポンスヘッダーで柔軟に制御できます。

Cloudflareと共同で本仕様を提案している Akamai・Fastly からも本機能が順次リリースされると思われ、サポートするCDNサービスが他にも増えるにつれて、本ヘッダーの魅力も増しそうです。

様々なCDNを飼い慣らしたい人には、大注目の仕様です。

更新

RFC 化

本エントリで紹介している"Targeted HTTP Response Header Fields for Cache Control" は RFC 9213: Targeted HTTP Cache Control として2022年6月に公開されました。

Akamai 対応

2021年6月に Akamai からも CDN-Cache-Control 対応が発表されました。

Akamai Blog | Targeted Cache Control

Akamai の場合、20年以上前から対応していた Edge-Control の標準化です。

参考