キャッシュが効かなかった

あるアプリケーションを使用していてCloudfrontのキャッシュがどうにも効かないので
原因を探っていました。発生した現象はこんな感じです。
1回目:Miss from Cloudfront
2回目:Miss from Cloudfront
3回目:Hit from Cloudfront

3回目にして効いているので何かの勘違いかな?と思っていたのですがどうも違う。
ブラウザを変えても、端末変えても同じ結果になる。

Cookieが原因

ミドルウェアによってはCookieをスルーしなければならないのがあります。原因を探っていたらここに行き着きました。
確かにForward CookieをAllにしている
1回目: ブラウザには Cookie が無い(あるいは古い)
このとき、Cookie がセットされる

2回目: ブラウザに Cookie が存在する
→1回目のリクエストとは Cookie の値が異なるためキャッシュオブジェクトが利用されず、Miss となる

3回目: ブラウザに Cookie が存在する
→2回目のリクエストと同じ Cookie であるため、Hit となる
と言う結論。

なぜCookieを使うとHitしないのか

なぜCookieを使うとHitしないのかと言うことですが、答えは簡単でCookieが付与されているとキャッシュサーバは
違うコンテンツと判断します。ですのでCookieごとにキャッシュするような形になります。Cookieが同じ値であれば
いいのですが、アプリケーションによってはそうも行きません。

回避方法

Cookieを必要としないコンテンツが必ずあるはずです。このコンテンツをCookieを付与しないことにします。
私が今回した設定は「画像系」「CSS系」「過去のコンテンツ」です。

まず、Cloudfrontの「Behavior」タブでファイルの拡張子を指定します。今回はjpgやgifなどを指定しました。
ここでの正規表現の書き方ですが、
「*.jpg」とすると全てのjpgファイルが対象になります。特定のパスのjpgファイルだけの場合は
[/path1/*.jpg」としましょう。この場合は「/path1/path2/*.jpg」も対象になります。
cloudfront01

次にbehaviorの設定を開いて「Forward Cookie」を「None」にすればCookieがjpgファイルには適用されません。
Cloudfrontは上に書いた内容が優先されます。
cloudfront02

Expiresが反映されない?

先ほどのbehaviorの設定で、MinimumTTLの設定を大きくしたにもかかわらず、「Cache-Control: public, max-age=600」
と設定していると、下記のように表示されます。

# curl -I http://hoge.com/
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Cache-Control: public, max-age=600

これはキャッシュが600秒しか効かないのか?と思われるかもしれませんが
これは、オリジン(ようはサーバ)が Cache-Control max-age を返し、
CloudFront の Minimum TTL が設定されている場合には、
CloudFront キャッシュにはどちらか大きい方の値の時間キャッシュされます。
しかし、クライアント側のブラウザでは、CloudFront に設定された
Minimum TTL に関係無く、Cache-Control max-age に設定された値だけキャッシュ致します。

例えばCloudfrontのMinumTTLを86400(24時間)としていた場合は、
クライアントブラウザ(600秒キャッシュ)→Cloudront(24時間キャッシュ)→オリジン
となります。24時間の間はキャッシュされたらオリジンへアクセスは行きません。
MinimumTTLを設定していなかった場合は
クライアントブラウザ(600秒キャッシュ)→Cloudront(600秒キャッシュ)→オリジン
となります。

状況に応じたCloudfrontの設定

Cookieが必要だからといってCloudfrontをあきらめないでどこかで必ず抜け道(Cookieを使用しなくても良い)部分があるはずです。今回は画像系のファイルをご紹介しましたが、特定のファイルやURLではキャッシュを使ってもOKだったりします。

クラウドデザインパターン実践ガイド

クラウドデザインパターンが販売されていますが、これが絶対ではありませんが一通り目を通すと参考になるかと思います。