share facebook facebook twitter menu hatena pocket slack

2012.03.30 FRI

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

WRITTEN BY 後藤 和貴

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"

このようにファイルの置き場所やファイル名は一切変えずにパスだけを変えてファイル更新を
実現することができました。

こちらの記事はなかの人(klog)監修のもと掲載しています。
元記事は、こちら

後藤 和貴

執行役員 / エバンジェリスト。外向けにはイベントや勉強会などで講演する役割。社内ではマーケティング全般と新商品企画やPR戦略などを担当しています。