![]()
Amazon CloudFrontの使用上の注意とTipsまとめ

フナミタカオです。
11月19日に公開された、AmazonCloudFrontですが、高速転送ができるのはわかったのですが、ファイルの更新タイミング等いくつか気になることがありました。調べてみたところ、例えば「オリジナルサーバー側でファイルの内容を更新あるいは削除しても、エッジサーバーには、すぐ反映されない」ということがわかりました。サービスの作りによっては致命的な制約にもなりかねない話なので、本番で使う前に確認したい点をまとめてみます。また、独自ドメインの設定方法やgzipで配信する方法等、Tipsもまとめてみました。
CloudFrontの情報源
CloudFrontについての情報は、公式サイトの開発者向けドキュメントと、サポートフォーラムをのぞくのがいいです。開発者向けドキュメント
・デベロッパーガイド
Amazon CloudFront Developer Guide (API Version 2008-06-30)(PDF版|HTML版)
設計思想から、キャッシュの制限や制御方法が詳細に説明されています。PDF版とHTML版があります。PDF版で67ページ。量的にもそれほど、多くないので、ぜひ、熟読しましょう。
・Getting Started ガイド
Amazon CloudFront Getting Started Guide (API Version 2008-06-30)(HTML版)
デベロッパーガイドのサマリー。試しに使ってみるには、このドキュメントだけでも十分だけど、実際に本番運用を検討するなら、デベロッパーガイドは必読。
サポートフォーラム
英語だけですが、大体の思いつく疑問はここで、議論されています。Amazonのスタッフのコメントもあり、疑問点と、拡張提案が数多く投稿されています。
また、ログインすると、未読既読もわかる、便利なフォーラムになっています。
Amazon Web Services Developer Community : Amazon CloudFront (Beta)
このエントリも、元ネタとして、このフォーラムを参考にさせていただきました。
FAQ
http://aws.amazon.com/cloudfront/faqs/ FAQもいい感じにまとめられています。
キャッシュの大まかな仕組みと、コンテンツの向き不向き
CloudFrontは、高速にファイルを配信することが可能ですが、そのために、ユーザーの近くにエッジサーバーと呼ばれるサーバーを配置しています。
エッジサーバーは、ヨーロッパ、北米、アジアに配置されていますが、逆にいうとこれら以外のエリアでは、エッジサーバーの恩恵は受けられないということです。
キャッシュされるファイルの原本は、AmazonS3におかれたファイルで、AmazonS3はオリジナルサーバーと呼ばれています。
では、オリジナルサーバーにおかれたファイルは、どのようにしてエッジサーバーに配信されるのでしょうか?
1.ファイルを配信したいと思っているあなた(You)がまずオリジナルサーバー(S3)にファイルを配置
2.そのファイルがおかれている、バケットをdistributionする。このdistribution.によって、特定のバケットにたいして、CloudFront経由でアクセス可能なURLが発行される。
3. ユーザーはCloudFront経由でアクセス可能なURLを使って、アクセス。エッジサーバーにキャッシュがあれば、それを返す。
4.もし、エッジサーバーにキャッシュがなければオリジナルサーバー(S3)からエッジサーバーにコピーして、それを返す。
という流れで、ポイントは
「エッジサーバーにキャッシュがなかったら、オリジナルをオリジナルサーバー(S3)にとりにいく」
という点です。
事前に、すべてのエッジサーバーに配布している訳ではなくて、必要になってから、オリジナル(S3)->エッジのコピーがおこるということです。
そして、実はこのオリジナル(S3)->エッジのコピーが高速かというと、そうでもなくて、通常のS3からユーザー間と同程度(あるいは、もう少し遅い)ようです。なので、あまり参照されないファイルだと、キャッシュされていない確率が高く、高速化されなくなってしまいます。
また、料金体系は、
・オリジナル(S3)->エッジサーバーへの転送料
・エッジサーバー+ユーザー間の転送料
の2つがあり、同一ファイルであれば、オリジナル(S3)->エッジサーバー間の転送料は1回分で、あとは、エッジサーバー+ユーザー間の転送料がのみです。
エッジサーバー+ユーザー間で数百〜数万のレンジで転送されれば、S3->エッジサーバー間の料金は数百〜数万で案分されて、微々たる額になりますが、エッジサーバー+ユーザー間が1回しかないと、S3->エッジサーバーの転送料+エッジサーバー+ユーザー間の転送料がかかり、かつ転送速度も速くない(1回目のキャッシュ時は速くないので)ということになってしまいます。
Amazon CloudFront or Amazon S3?というページには
最も人気のあるコンテンツを配信するのに向いています。恒久的なストレージではないです。頻繁にダウンロードするファイルはエッジサーバーにおかれていますが、あまりアクセスされないファイルはエッジサーバーから、削除されてしまいます。(CloudFront is designed to distribute your most popular content with low latency. It is not designed for durable storage. Copies of your popular objects are stored in edge locations close to end users on the Internet; if an object isn’t accessed frequently it might be removed from an edge location. )
と、書かれています。
つまりすべてのページで読み込まれるjsやcss、ロゴ画像とかには最適ということですね。
画像共有サービスなどは、人気のコンテンツと、そう出ないコンテンツが混じっているので、もしかすると、人気のないコンテンツの為に、転送料がかさんでしまうということがおこるかもしれません。
ファイルのダウンロード状況にあわせて、動的に配信サーバーを変えられるとベストですが、そのためには、アプリ側での実装が必要になってきます。
ということで、一番向いているのは、公式ドキュメントにも書かれているように「少数のファイルだけど、大量にリクエストされる」ケースですね
例えば、メディアテクノロジーラボで運営しているコマーシャライザーでは、CMは現在 約14000 件(11月25日現在)あります。CMごとに、その素材(写真)は異なりますが、bgmは35種類です。
このケースの場合ではこの音楽ファイルをCloudFrontにおくのがぴったりです。
逆にCMごとに異なる、写真については、再生頻度の高いCMについてはCloudFrontおくのは効果的ですが、再生頻度が低いCMについては、転送コストのメリットも出にくくなるでしょう。
コマーシャライザーのケースでは、音楽ファイルは、追加はされますが、削除、更新はないので、完璧ですね。削除更新が頻繁にあると、オリジナルサーバーでの変更が、すぐには、エッジサーバーには伝わらないので、要注意となります。
では、この後は、ポイントを箇条書きで並べてみます
1.削除、更新はいつ反映されるのか?
エッジサーバーへは、リクエストがあったときに、もし、そのファイルが無かったら、オリジナルサーバーから、コピーされます。では、このエッジサーバーにおかれた、ファイルを削除するには、どうすればいいのでしょうか?あるいは、オリジナルサーバー側を更新したとして、その更新はいつ反映されるのでしょうか?
エッジサーバーのキャッシュはデフォルトで24時間
Amazon CloudFront and Your Live System>Other Things You Should Know>Object Expiration によるとAn object stays in an edge location until it expires. After the object expires, CloudFront must go back to the origin server the next time that edge location needs to serve that object. By default, all objects automatically expire after 24 hours. オブジェクトはエッジサーバーに有効期限が切れるまで、おかれます。オブジェクトの有効期限が切れると、次にエッジサーバーに必要になったときに、オリジナルサーバーから、コピーされます。デフォルトでは有効期限は24時間に設定されています。とのことです。
つまり、一度、エッジサーバーにコピーされると、オリジナルを変更しても、その反映は最大24時間後ということになります。
また、この24時間は、エッジサーバーにコピーされたタイミングからなので、エッジサーバーごとに、どのコピー時刻も異なる可能性があり、正確な時刻が予想できないのが難点です。(始終ダウンロードされるようなファイルであれば、時間は似かよるとは思いますが...)
また、デフォルトで24時間ですが、 Cache-Control, Pragma, かExpires ヘッダをつけることで、指定することは可能です。ただし、24時間以下にはできません。
よって、更新にしろ、削除にしろ、24時間くらいずれても、いいコンテンツでないとCloudFront には向かないことになります。
写真共有サイトでつかう場合だと、写真の加工とかがあった場合は、必ずファイル名を変更するような対応が必要です。
広告バナー等で期限を設定して、配信を停止する必要があって、正確に時刻を指定したいなら、エッジサーバーのファイルを削除するのではなくて、distributionをDisabledすれば数分でそのdistributionに対応したドメイン(例:http://d1hgczh9r2kbjm.cloudfront.net/002.jpg)配下のファイルを見えなくすることはできました。distributionは1つのアカウントに対して100個まで持つことが可能ということなので、うまくグループ分けすれば、配信停止を必要なタイミングで行うことも可能になりそうです。
じゃあ、更新のときも、いったん、対象のdistributionをDisabledにして、オリジナルサーバー側のファイルを上書き更新した後、そのdistributionをEnabledにすれば、任意の時刻に更新もできそうですが、残念ながらEnabledになったときにもエッジサーバー側のファイルは削除されている訳ではないので、引き続き上書き前のファイルが表示されてしまいました。
ドメインの解決ができなくなっただけ(見えなくなってただけ)でキャッシュには、影響を与えることができないようです。
時間を意識しての、削除・更新には向かないということですが、
Versioning Objects
には
Versioning means that you assign each object in the origin server a version number. For example, instead of calling the file image.jpg, you call it image_1.jpg. Then when you want to start serving a new version of the file, you name that new file image_2.jpg, and you update your links to point to image_2.jpg. With versioning, you do not have to wait for an object to expire before you can serve a new version of it.
ファイル名を変えてバージョニングしてください。そして、リンク先をそれにあわせて変更してください。
とのことです。
・画像を更新前
<body>
.....
<img src="http://d1hgczh9r2kbjm.cloudfront.net/image_1.jpg">
.....
</body>
・画像を更新後
<body>
.....
<img src="http://d1hgczh9r2kbjm.cloudfront.net/image_2.jpg">
.....
</body>
この例だと画像を貼り込む側のHTMLの変更が必要なので、静的ページには向きませんし、ある画像のファイル名を管理するために、FTPでは無くて、専用のアップローダーが必要になってくると思います。そのアップローダーは、ファイル名を採番すると同時に、HTMLを書き換えるということが必要になります。(うーん、大変。)
有効期限はのばすことは可能だが24時間以下にはできない
参考:Object Expire Times
エッジサーバー側のファイル(オブジェクト)の有効期限を設定することはできますが、24時間以下にすることはできません。
24時間以上であれば、任意に設定可能で、無期限という設定もOKです。
もし、まったく変更が無いファイルであれば、無期限に設定しておくことで、オリジナルサーバーからエッジサーバーへの転送料がかからなくなります。しかし、無期限にすると、削除自体することができなくなるので、要注意です。
「任意の時間にエッジサーバー側のファイルを削除できないのか?」
という問い合わせがフォーラムで何度か出ていますが、リリース予定はあるとのことですが、初期リリースには含まれていません。
任意にエッジサーバー側のファイルを削除をできれば、更新も任意に可能ということになりますよね。ただ、数多く存在するであろう、エッジサーバーに対して、ファイル単位で削除をするとうことの負荷を考えて、初期リリースはしなかったのかもしれません。
ExpireヘッダーはS3でつけたのもが、反映される
参考:Object Expire Times
参考:Webサイトの高速化 ルール3 Expiresヘッダーを追加しよう! (Yahoo! developer netoworkより翻訳)
有効期限を制御するためにExpireヘッダーをつけるということですが、このヘッダの指定は、S3で行います。
Cache-Control: max-age=21600,s-maxage=86400
Expires: Sun, 23 Nov 2008 21:11:04 GMT
1. Expiresを "expire immediately"のような間違った設定は無視される。最低でも24時間後に設定される。
2. max-ageも同じく間違った指定は無視。最低でも24時間後に設定
3. Expires と max-age の両方が指定されたときは, max-ageの値が不正でも、Expires は無視される
Expireヘッダーの付け方。
ヘッダーの変更はFirefox Organizerではできなさそうなので、別のツールが必要。
Rubyの場合だと、RightScale's AWSがおすすめです。
以下はbucket:test, key:100.txtという既にアップ済みのファイルのヘッダを変更する方法。key.putのパラメーターで再度、dataも含めて、セットしています。Content-Typeもつけないと、Content-Type=""になってしまいます。
require "rubygems"
require "right_aws"
s3 = RightAws::S3.new([aws_access_key_idを入力], [aws_secret_access_keyを入力])
bucket = s3.bucket("test")
key = RightAws::S3::Key.create(bucket, '100.txt')
if key.exists?
data = key.get
key.put(data,'public-read',{"Expires" => "Thu, 14 Apr 2010 20:00:10 GMT","Content-Type" =>"text/plain"})
end
依存ファイルが反映されているとは限らない
同名のファイルはS3で上書きしても、CloudFlontの更新には時間差があります。最大24時間かかるわけですが、もし、JavascriptやFlash等で、依存するライブラリがあるときには、複数のファイルをS3で更新しても、CloudFlont上での更新は、複数ファイルの同期がとれることはないです。
依存関係のあるファイルを集めて1つのディレクトリに入れておく等、気遣いが必要になります。
QueryStringは無視される。sample.jpg?a=1は効果無し
ブラウザのキャッシュを防ぐために、QueryStringにタイムスタンプや、連番のようなパラメータを付け加えることがありますが、CloudFrontはこのストリングを無視します。
なので、この方法で、キャッシュしていないコンテンツを取り出すことはできません。
2.セキュアなコンテンツには向かない
S3の公開は全員に公開できるようにしておく必要がある
参照:What would be the recommended way of securing content on CloudFront ?
CloudFrontで公開される、ファイルはS3で全員に公開の状態になってる必要があります。
クローズドな公開には向きません。
リファラーによる配信制限はできない
参照:Thread: Referrer checking? リファラーを見て、通信制限することもできません。httpsはサポートされない
参照:CloudFront doesn't work with HTTPS requests? httpsがサポートされていません。 よって、httpsに貼り込まれるような、画像を配信すると、ブラウザによっては、警告が出てしまいます。S3はhttpsもサポートされるのですが、初期リリースではhttpsはサポートされませんでした。3.独自ドメインでの配信方法
参照:http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/index.html?CNAMEs.html CNAMEを設定することで、独自ドメインと、CloudFlontの配信ができるようになります。 Firefox OrganizerでもManage distributionsメニューからCNAMEの設定が可能です。
4.gzipでの配信は工夫すれば可能
参照:Content-encoding: gzip for text files
gzipはサポートしてないけど、zipしたファイルを作って、'Content-Encoding' => 'gzip',のようなヘッダも用意すれば大丈夫とのことです。
5.Amazon CloudFront (Amazon’s CDN)にも対応しているS3のブラウザ
・S3Fox Organizer for Amazon(S3Fox) v0.4.5
FireFoxのプラグイン。一番簡単だと思います。
・bucket Explorer
有償(49.99ドル)のクライアントアプリ。体験版もある。Mac,Win版あり。
いろいろできそうだけど、S3Fox Organizer でも十分かも。
