michimani.net

Amazon CloudFront のキャッシュ仕様についてあらためて調べてみた

2020-04-03

Amazon CloudFront は AWS が提供している CDN サービスで、 AWS 環境で Web アプリケーションを運用する際に利用することが多いと思います。このブログの運用にも使用しているのですが、ふと CloudFront のキャッシュ仕様について気になったので、あらためて調べてみました。

気になったきっかけは先日書いたブログ記事です。

目次

前提

CloudFront の Web Distribution において、 オリジンに S3 を指定している場合 のキャッシュ仕様について自分なりにまとめたものになります。公式ドキュメント以上の内容はありません。
また、 RTMP Distribution または Web Distribution でカスタムオリジンを指定している場合は挙動が変わる部分もあるので、詳細は公式ドキュメントを参照してください。

ちなみに、RTMP Distribution は 2020/12/31 でサポートが終了するみたいです。

触れること

今回は、 Amazon CloudFront (以下、 CloudFront) のキャッシュ仕様について調べてみた内容をまとめます。具体的には、 Web Distribution の Behavior の設定画面で出てくる項目のうち、次の項目についてです。

設定画面では下のキャプチャ内で赤枠で囲った部分です。

CloudFront Behavior setting

各項目の概要

上であげた項目の詳細の前に、簡単にそれぞれの項目が何を設定する項目なのか、概要をおさらいします。

Cached HTTP Methods

キャッシュ対象とする HTTP メソッドを指定します。

Cache Based on Selected Request Headers

リクエストヘッダの情報をもとにキャッシュするかどうかを指定します。

Object Caching

キャッシュ時間を指定します。

Forward Cookies

Cookie をもとにキャッシュするかどうかを指定します。

Query String Forwarding and Caching

クエリパラメータをもとにキャッシュするかどうかを指定します。

各項目の詳細

では、各項目の指定内容と仕様についてまとめていきます。

Cached HTTP Methods

キャッシュ対象とする HTTP メソッドを指定します。デフォルトで GETHEAD はキャッシュ対象になっており、対象から外すことはできません。

Allowed HTTP Methods の指定方法によって、選択できる HTTP メソッドが下記のように変わります。

「GET, HEAD」を指定した場合

デフォルトの GETHEAD のみキャッシュ対象となります。

「GET, HEAD, OPTIONS」 または「GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE」を指定した場合

デフォルトの GETHEAD に加えて OPTIONS もキャッシュ対象にすることが可能です。

Cache Based on Selected Request Headers

CloudFront は、デフォルトではオリジンのオブジェクトをキャッシュする際にリクエストヘッダは考慮されません。なので、例えば下記のように custom-header に別々の値を指定してリクエストしても、 どちらか一方のみがキャッシュされる ことになります。

GET /get HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: httpbin.org
User-Agent: HTTPie/2.0.0
custom-header: foo
GET /get HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: httpbin.org
User-Agent: HTTPie/2.0.0
custom-header: bar

Cache Based on Selected Request Headers の項目では、リクエストヘッダをもとにキャッシュするかどうかを、次の 3 つの方法でしていします。

None (Improves Cacheing)

オブジェクトをキャッシュする際に、リクエストヘッダは考慮されません。上であげた例の通り、特定のヘッダの値が異なっていても、どちらか (複数のパターンが有る場合はどれかひとつ) のオブジェクトをキャッシュします。
デフォルトではこの方法が指定されています。

Whitelist

明示的に指定したリクエストヘッダの値に基づいてオブジェクトをキャッシュします。たとえば、上の例で使用した custom-header というヘッダをホワイトリストで指定した場合、 custom-header: foocustom-header: bar は別々にキャッシュされます。
Behavior の設定画面ではこの方法を指定するとテキストエリアが表示されるので、キャッシュ対象としたいリクエストヘッダ名を改行で区切って指定します。

CloudFront はデフォルトでいくつかのリクエストヘッダをオリジンに転送しますが、キャッシュ対象となるのはホワイトリストで指定したヘッダのみです。また、ホワイトリストに指定できるヘッダの上限は、 10 となっています。この数を超えて指定したい場合は、クォータの引き上げリクエストをする必要があります。

All

すべてのリクエストヘッダをオリジンに転送します。その代わり、この設定をした場合 CloudFront は、 この Behavior で対象となるオブジェクトをキャッシュしない ようになります。

Object Caching

CloudFront がオリジンのオブジェクトをキャッシュし、再度オリジンにリクエストを転送するまでの時間 (キャッシュに保持する時間) を指定します。ここで指定した時間、キャッシュは CloudFront のエッジロケーションに保持され、オブジェクトはそこからビューアへ返却されます。

ただし頻繁にアクセスが無いオブジェクトに関しては、キャッシュ保持時間に達する前にエッジロケーションから削除される場合もあります。

デフォルトでは 24 時間 (86400 秒) 後にキャッシュの有効期限が切れるようになっていますが、次の 2 つの方法でキャッシュ時間を制御します。

Use Origin Cache Headers

オリジンのオブジェクトに指定されている Cache-Control: max-age または Cache-Control: s-maxage または Expires ヘッダの値をもとにキャッシュ時間を制御します。これらのヘッダがオリジンのオブジェクトに存在しない場合は、デフォルトの 24 時間 が適用されます。

各ヘッダの指定方法の例は下記のようになります。

CloudFront では Cache-Control: max-ageCache-Control: s-maxage を併用することができます。また、 Cache-Control: max-ageExpires を両方指定した場合、 CloudFront は Cache-Control: max-age の値を使用します。 挙動については後述します。

Customize

デフォルトでは 24 時間となっているキャッシュ時間を、 最小 (Minimum TTL)最大 (Maximum TTL)デフォルト (Default TTL) の 3 つの値で指定します。各値が適用される条件については後述します。

キャッシュの保持時間の挙動

実際に CloudFront のエッジロケーションでキャッシュが保持される時間、およびブラウザでのキャッシュ保持時間は、オリジンのオブジェクトのヘッダ情報と、Minimum/Maximum/Default および CloudFront のデフォルト (24h = 86400sec) の条件によって変わります。具体的には下記の条件の組み合わせになります。

オリジン

CloludFront

※表内では表記の都合上、 Minimum TTL、 Maximum TTL をそれぞれ MIN と MAX と書いてます

オリジン Minimum TTL = 0 Minimum TTL > 0
Cache-Control: max-age あり CloudFront
max-age と Maximum TTL の小さい方の値

ブラウザ
max-age の値
CloudFront
・MIN < max-age < MAX の場合
 max-age の値

max-age < MIN の場合
 Minimum TTL の値

max-age > MAX の場合
 Maximum TTL の値

ブラウザ
max-age の値
Cache-Control: max-age なし CloudFront
Default TTL の値

ブラウザ
ブラウザによる
CloudFront
Default TTL または Min TTL のうち大きい方の値

ブラウザ
ブラウザによる
Cache-Control: max-age および
Cache-Control: s-maxage あり
CloudFront
s-maxage と Maximum TTL の小さい方の値

ブラウザ
max-age の値
CloudFront
・MIN < s-maxage < MAX の場合
 s-maxage の値

s-maxage < MIN の場合
 Minimum TTL の値

s-maxage > MAX の場合
 Maximum TTL の値

ブラウザ
max-age の値
Expires あり CloudFront
Expires の日付と Maximum TTL に対応する日付の早い方の日付まで

ブラウザ
Expires の日付まで
CloudFront
・MIN < Expires < MAX の場合
 Expires の日付まで

Expires < MIN の場合
 Minimum TTL に対応する日付まで

Expires > MAX の場合
 Maximum TTL の値に対応する日付まで

ブラウザ
Expires の日付まで
Cache-Control: no-cacheno-storeprivate のいずれかあり CloudFront
ヘッダを優先

ブラウザ
ヘッダを優先
CloudFront
Minimum TTL の値

ブラウザ
ヘッダを優先

より詳細な表については下記公式ドキュメントを参照してください。

Forward Cookies

CLoudFront では、デフォルトでキャッシュに Cookie が考慮されません。この項目ではオリジンに Cookie を転送し、 Cookie の値によってキャッシュをするかどうかを次の 3 つの方法で指定します。

None (Improves Caching)

Cookie をオリジンに転送せず、キャッシュに考慮しません。また、リクエストヘッダから Cookie ヘッダを削除し、レスポンスヘッダから Set-Cookie ヘッダを削除します。

Web Distribution ではオリジンによって Cookie を処理しないパターンがあり、その場合はこの方法を指定するべきです。今回の前提としている S3 は Cookie を処理しないため、この項目では None を指定します。
S3 の他、 Cookie を処理しないオリジンの場合に None 以外を指定するとパフォーマンスの低下に繋がります。

Whitelist

ホワイトリストで指定した Cookie のみオリジンに転送し、その値をもとにキャッシュを保持します。指定した Cookie 以外はオリジンへの転送時に削除されます。一方、指定していない Cookie がオリジンからのレスポンスに含まれていた場合は、その値も含めてビューアに返却します。
指定方法はリクエストヘッダの場合と同様で、改行区切りで指定します。

All

すべての Cookie をオリジンに転送し、その値をもとにキャッシュを保持します。キャッシュに考慮されるのはリクエスト時に含まれていた Cookie のみで、リクエストには含まれずオリジンからのレスポンスには含まれるような Cookie はキャッシュに考慮されません。
ビューアへのレスポンスには、リクエストとオリジンからのレスポンスの両方の Cookie がすべて返却されます。

Query String Forwarding and Caching

リクエスト URL に含まれる ? 以降の文字列で指定されたクエリパラメータをもとにキャッシュを保持するかを指定します。指定方法は次の 3 です。

None (Improves Caching)

クエリパラメータをオリジンに転送せず、キャッシュに考慮しません。つまり、下記のリクエストではすべてキャッシュされるのはどれか一つのみとなります。

- https://michimani.net/js/bundle.js
- https://michimani.net/js/bundle.js?query_param=value1
- https://michimani.net/js/bundle.js?query_param=value2

Foward all, cache based on whitelist

ホワイトリストで指定したパラメータのみオリジンに転送し、その値をもとにキャッシュを保持します。例えば上の例で使用した query_param というパラメータをホワイトリストで指定した場合、上の 3 つは別々にキャッシュされます。一方で、指定していないパラメータはキャッシュに考慮されないため、下記のリクエストはすべて同一とみなされます。

- https://michimani.net/js/bundle.js
- https://michimani.net/js/bundle.js?query_param_2=value1
- https://michimani.net/js/bundle.js?query_param_2=value2

下記も同一となります。

- https://michimani.net/js/bundle.js?query_param=value1&query_param_2=value2_1
- https://michimani.net/js/bundle.js?query_param=value1&query_param_2=value2_2

Foward all, cache based on all

すべてのクエリパラメータをオリジンに転送し、その値をキャッシュに考慮します。

クエリパラメータによるキャッシュの注意点

クエリパラメータによるキャッシュを利用する場合に注意したいのが、 パラメータの順序パラメータの値の大文字/小文字 です。これらに注意しないと、オリジンへの不要なリクエストが発生し、パフォーマンスが低下する可能性があります。

パラメータの順序

例えば下記の 2 つのリクエストがあるとします。

- https://michimani.net/images/2020040220492101.jpg?width=1200&height=900&color=brack
- https://michimani.net/images/2020040220492101.jpg?height=900&color=black&width=1200

オリジンからすればどちらも width: 1200, height: 900, color: black のパラメータですが、CloudFront ではこれらは別々のキャッシュとして保持されます。

パラメータの値の大文字/小文字

パラメータの順序と同様に、パラメータ名および値の大文字/小文字について注意が必要です。

- https://michimani.net/images/2020040220492101.jpg?color=brack
- https://michimani.net/images/2020040220492101.jpg?Color=brack
- https://michimani.net/images/2020040220492101.jpg?color=Brack
- https://michimani.net/images/2020040220492101.jpg?Color=Brack

もしオリジン側では大文字/小文字を区別していなかったとしても、 CloudFront では上の 4 つはすべて別々のキャッシュとして保存されます。

まとめ

Amazon CloudFront において、 Web Distribution で S3 をオリジンに指定した際のキャッシュの仕様についてあらためて調べてみた話でした。
これまでなんとなく指定していた項目 (特にキャッシュ保持時間) もあって、やっぱり公式ドキュメントをしっかり読むのは大事だなと思いました。逆に言えば、 AWS は公式ドキュメントが非常に充実していて読みやすいということが言えると思います。

今回これだけの内容をまとめるのに結構時間がかかりましたが、まだまだ触れられていない内容もたくさんあります。もう疲れたのでこれ以上は書きませんが、今後も公式ドキュメントをしっかり読む癖は続けていきたいと思います。


comments powered by Disqus