カテゴリー
technology

CloudFrontでキャッシュ時間を長くしながらも運用作業量を下げる方法

amazon web services logo
CDNを使うのはキャッシュ目的であることがほとんどですが、スムースなアクセスを実現するにはキャッシュする時間を長くすべきです。もし無期限に設定したら1度オリジナルファイルを読めば後はCDNのサーバーまかせにできるので非常に効果的ですね。
しかし実際のサイトを運営していくのは必ずファイル更新作業があり、この同じファイルの更新の場面でCDNが入っていることで問題なります。キャッシュ時間を長くすることと更新を反映させることはCDN使う上では相反する行為だからですね。
世の中ではこうした問題を軽減するための手法がいくつか存在します。その一つがファイル名にバージョンを入れるRevving Filenamesという手法です。
要するに更新があったら「test.1.0.1.jpg」のようにファイル名にバージョン番号などを入れることで違うリソースとして認識させる手法のこと。これ完全に自動化されたデプロイ環境ならいいけど、手動でこれをするのは手間が多すぎしミスも発生しそう。
今回は、仮にHTML生成がアプリだとしてHTML中のパスを変えるのは簡単で、静的ファイルのファイル名を更新管理するのが難しいケースにしぼって、この問題を少しでも軽減すべくCloudFrontとEC2で試してみました。


前提としては、以下の通り。
・ファイル更新者はバージョン番号など入れずにいつもの通りファイル更新できる
・アプリでは画像のなどのパスを簡単に変更可能
まずEC2上のApacheの設定はこんな感じです。Expireヘッダー追加。1ヶ月キャッシュする設定。加えて /vXXX/(Xは数字)というパスを無視する設定。ドキュメントルート直下の「v」付のパスを無視するので「/v2/img/test.jpg」のようなアクセスには「/img/test.jpg」と内部で理解して画像を返すだけになります。

ExpiresActive On
ExpiresDefault "access plus 1 month"
RewriteEngine  on
RewriteRule    ^/v[0-9]*/(.*)  /$1  [PT]

このEC2へ向けたCloudFrontではパスを変えなければ1度アクセスしたファイルは1ヶ月間再アクセスしません。ファイル更新があったら「/vXXX/」を付け加えれるか数字を変更するだけ。
CloudFront経由で1度目のリクエストをしてみます。

$ curl -I http://d2tm6aw44wcrbw.cloudfront.net/img/test.jpg
HTTP/1.0 200 OK
Date: Tue, 27 Mar 2012 07:12:13 GMT
Server: Apache/2.2.22 (Amazon)
Last-Modified: Tue, 27 Mar 2012 07:11:54 GMT
ETag: "202de-1bf50-4bc3434a08760"
Accept-Ranges: bytes
Content-Length: 114512
Cache-Control: max-age=2592000
Expires: Thu, 26 Apr 2012 07:12:13 GMT
Content-Type: image/jpeg
X-Cache: Miss from cloudfront
X-Amz-Cf-Id: EOrigK-aBfRHo4KPpp7CgAZUT0pb07l8Tzy5DYoadCemegctIIkCVg==,An6PZuCBnIBjuY7FJNPa_tSvRvPkLbutAoqwp-QDxTY148bwU2PEkA==,7JJ6bolg3h3mQKAWBLlOIHgvcRj-Xb1zCQ-OPTTQ0wp5Ct7-WZMC7w==
Via: 1.0 ad24b1fd4aff5951d51e7e0f2f730c0b.cloudfront.net (CloudFront)
Connection: close

するとEC2上のApacheログではアクセスされた記録が残ります。
(上記のX-Cacheヘッダーにも「Miss from cloudfront」とありますね)

216.137.52.64 - - [27/Mar/2012:07:12:13 +0000] "HEAD /img/test.jpg HTTP/1.0" 200 - "-" "Amazon CloudFront"

2度目に同じURLへアクセスをしてもログには何もでません。当然アクセスしてないため出ません。
(X-Cacheは「Hit from cloudfront」となっていてキャッシュヒットしたことを表してます)

$ curl -I http://d2tm6aw44wcrbw.cloudfront.net/img/test.jpg
HTTP/1.0 200 OK
Date: Tue, 27 Mar 2012 07:12:13 GMT
Server: Apache/2.2.22 (Amazon)
Last-Modified: Tue, 27 Mar 2012 07:11:54 GMT
ETag: "202de-1bf50-4bc3434a08760"
Accept-Ranges: bytes
Content-Length: 114512
Cache-Control: max-age=2592000
Expires: Thu, 26 Apr 2012 07:12:13 GMT
Content-Type: image/jpeg
Age: 226
X-Cache: Hit from cloudfront
X-Amz-Cf-Id: l0LBQIqIxcu2nDo1iKI4LlqUXM11OdWKidnVNc39kOV4ou-YH6eiMg==,HX6LoFlUcESJUhfb81X0RiZBpgiD-Of_y9CqPoiqKdnRTgvvWsLGfw==
Via: 1.0 23ebd0f161b523c5675721fc89f813b9.cloudfront.net (CloudFront)
Connection: close

ここで同じファイルを同じ場所で更新した前提でURLに /v2/ を追加してみます。

$ curl -I http://d2tm6aw44wcrbw.cloudfront.net/v2/img/test.jpg
HTTP/1.0 200 OK
Date: Tue, 27 Mar 2012 07:15:40 GMT
Server: Apache/2.2.22 (Amazon)
Last-Modified: Tue, 27 Mar 2012 07:11:54 GMT
ETag: "202de-1bf50-4bc3434a08760"
Accept-Ranges: bytes
Content-Length: 114512
Cache-Control: max-age=2592000
Expires: Thu, 26 Apr 2012 07:15:40 GMT
Content-Type: image/jpeg
X-Cache: Miss from cloudfront
X-Amz-Cf-Id: B6YTDO3U3Y0Bwmxk3oWEWgXrSrhZ5ZM7-F4MhwyP_afZ8jxnVfdiHw==,6Us2F8ffb1KX7ISKXx8ir_x9frYfKdww5r10Aec9fgeU6BVsHgceqg==,PxaKaYsuAkjzxbBg34Ho0qicahSuY2XtG2iN7POjD-uN_9xr0nqbTA==
Via: 1.0 23ebd0f161b523c5675721fc89f813b9.cloudfront.net (CloudFront)
Connection: close

するとまたキャッシュがヒットしました。EC2のアクセスログにも記録がでました。

216.137.52.64 - - [27/Mar/2012:07:12:13 +0000] "HEAD /img/test.jpg HTTP/1.0" 200 - "-" "Amazon CloudFront"
216.137.52.64 - - [27/Mar/2012:07:15:40 +0000] "HEAD /v2/img/test.jpg HTTP/1.0" 200 - "-" "Amazon CloudFront"

このようにファイルの置き場所やファイル名は一切変えずにパスだけを変えてファイル更新を実現することができました。おしまい。
ふぅ、ながながしく書いた割りにはたいしたことやってないけど、人に感心されたので他の人にも役に立つかもしれないのでポストしとく。