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」とあります)
1 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"
このようにファイルの置き場所やファイル名は一切変えずにパスだけを変えてファイル更新を
実現することができました。