必見の記事

AWSにおける静的コンテンツ配信パターンカタログ(アンチパターン含む)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

独自ドメインSSLだとCloudFront使えないから横綱無理だよねー、という話がありました。うん、確かにそうでした、執筆時点では…! 本日2013/06/12、CloudFrontの独自ドメインSSL対応が発表(英語日本語)されましたので、みなさん揃って横綱になればいいと思います。

よく訓練されたアップル信者、都元です。AWSを利用して構築した環境から、クライアント(モバイルやブラウザ等)に対してHTTPを使って静的なコンテンツを配信したいケースって、多いですよね。多いというか、むしろどんなシステムにも多かれ少なかれ、静的なコンテンツ配信があると思います。

スケーラビリティ・柔軟性・可用性・パフォーマンス・コスト

静的なコンテンツというのは、コンテンツをリクエストに応じて生成したりせず、完成品としてのファイルが手元にある状態です。例えば、多くのWebシステムにおいて、ほとんどの画像やJSやCSSファイルは静的コンテンツです。このようなファイル状のコンテンツは、AWSにおいて、どのような体制で配信するのが適切なのでしょうか。

…とか、あまり考えたことがないのではないのでしょうか。Webシステムやモバイルアプリにおいて、静的コンテンツの配信は「動的コンテンツの生成・配信のついで」程度で考えられてしまうことが多いです。しかし近年の静的コンテンツは、動画やARのモデリングデータ、音声等…、とにかくサイズがデカい。そんなところに、Yahoo!砲だのTVで紹介されただの、スパイクアクセスがやってきた日には、動的はおろか静的コンテンツでさえ配信が難しくなってしまします。静的コンテンツの配信を、ナメちゃだめです。

さてそんなわけで、AWS上での静的コンテンツ配信について本気出して考えてみると、様々な配信体制が想定できます。ここではスマホアプリに対して動画や音声のような静的コンテンツを配信するAPIサーバ的なものを想定します。この配信体制の例を列挙し、それぞれを

  • スケーラビリティ(アクセスが急増しても大丈夫だろうか?)
  • 柔軟性(配信体制を強化・変更したくなった時に、アプリに影響を与えずに上手く対応できるだろうか?)
  • 可用性(24/365でサービスを継続できるだろうか?)
  • パフォーマンス(転送速度は速いだろうか?)
  • コスト(維持費は安いだろうか?)

等の視点から考察してみたいと思います。

では、まずベストケースとワーストケースを見てみましょう。

横綱: S3 + CloudFront + Route53

1yokozuna

まずはコレ。ベストな状態です。アプリには api.example.com というホスト名が埋め込まれており、例えば http://api.example.com/image/foobar.png のようなURLで様々な画像にアクセスします。

アクセスが急増したとしても、CloudFrontがかぶさっていますので、高いパフォーマンスが発揮でき、オリジンに負荷を掛けることもありません。

配信体制を変更したい *1となった場合でも、Route53による独自ドメイン運用ですので、この指し先を変更することで、色々な配信体制に切り替えることが可能です。

可用性の面でも心配は無いでしょう。Route53のSLAは100%ですし、CloudFrontやS3についても、裏側が複数拠点分散体制になっていますので、AZが1つ丸ごとダウンしたとしても、サービスが継続できます。

コスト面でも、常時稼働のEC2インスタンスは必要ありませんので、非常に安く上がりますね。

序の口: EC2の自動割り当てホスト名

2jonokuchi

はい、この子は入門したての新弟子です。アプリにEC2の自動割り当てホスト名 *2をハードコーディングしていて、そのURLを利用して、EC2上のApacheなんかに画像を取りに行っているパターンです。

そもそも静的コンテンツをサーブしたいだけなのにEC2が立っているのがまずアレです。まぁ現実の事例としては「既に動的コンテンツ生成配信用として動かしてるサーバがあるから、そこに静的コンテンツも乗せちゃえー。S3とか言われてもよくわかんないしぃー。」的な発想ですかね。

配信体制を変更しようにも、アプリにホスト名がハードコーディングされているものだから、アクセスを別の体制に向けることがまずできません。アプリのバージョンアップすればいいじゃん、って思いました? 新しいバージョンを出したって、ユーザは全員アップデートしてくれるとは限らないのです。むしろ、必ず一定数が古いバージョンを使い続けます *3。その人たちを切り捨てる、という決断を、あなたはできるでしょうか? というわけで、簡単には身動きが取れません。

マルチAZに対応するのも困難でしょう。可用性についても雲行きが怪しい、ということです。

また、アクセスが急増した場合、まぁそんなにリッチなインスタンスは使っていないでしょうから、早々にパンクすることでしょう。スケールアップすればいいって? スケールアップする場合には、EC2インスタンスのSTOP/STARTが発生します。そうなった日にゃ最悪ですよ。STOP/STARTってことはホスト名(IPアドレス)変わりますよ? 元のホスト名は取り戻せません。世に出ているアプリのバージョンは使い物にならなくなり、強制的に新しいバージョンのリリースを迫られることになります。Appleの審査を待つ数日間は、永遠にも感じられることでしょう…。

身の毛も弥立つとは正にこのこと。このような配信体制は絶対に避けましょう。これぞ、THEアンチパターンです。

さて、最強と最弱をご紹介したわけですが、あとは弱い方から序二段・三段目……大関まで順に見て行きましょう。ここからはただ単に、序の口の悪夢が一つ一つ解消されて行くようなイメージで、少々退屈かもしれませんが、「あなたのシステムの配信パターンはどれ?」というカタログのような役割を果たせればと思います。んじゃ、一気にいきますよ?

序二段: EC2 + EIP

3jyonidan

アプリにハードコーディングされているのはEIP、これでSTOP/STARTによる悪夢からは逃れられるようになります。

ただし、もちろん複数台のインスタンス体制は組めませんので、可用性の点で問題があります。過大なアクセスに耐えるために、スケールアップ作業をする場合は、その間サービスをメンテナンス停止する必要がありますしね。

また、EIPがハードコーディングされているため、ELBやCloudFrontを利用しようとするのも難しい。出来なくはないですが。まずはEC2でリクエストを受けたら、301リダイレクトでCloudFront/ELBに飛ばす、ただしCloudFront/ELBからのアクセスは受け付けて、コンテンツを返す、といった仕組みをmod_rewirteに作り込めば、まぁなんとか…。

三段目: EC2 + ELB

4sandanme

ELB(ロードバランサー)を配備してみました。アプリにハードコードされるのはELBのDNS名です。

ELBがあるので、マルチAZ体制は組めます。スケールアップ時にも止まりませんので可用性問題は解決できました。序二段と同様、ここにCloudFrontを噛ますには、mod_rewiteでごにょごにょすることになります。

ちなみにこの子は昇進が望めません。ELBの配下にS3のバケットをくっつけられればなー。。。

ところで、この配信体制にはさらなる罠が待ち受けています。ELBの配下には複数のインスタンスを付けられる訳ですが、配信対象となる静的コンテンツが動的に増えて行く場合…。そうです。コンテンツが管理画面からのアップロードにより次々に追加されるようなケースです。ELB配下の全てのインスタンスに、新コンテンツを届けなければなりません。

NFSを組むことを考えるでしょうか? 1台マスターを決めて同期することを考えるでしょうか? そのマスターがSPOFになってしまいます。…でも、そうせざるを得ないのです。

結論として、コンテンツの動的追加がある場合、すなわち「配信するコンテンツごとAMIを取得して運用できる状態ではない」場合は、この体制 *4もアンチパターンと言って良いのではないでしょうか。

幕下: EC2 + ELB + CloudFront

5makushita

三枚目にCloudFrontを追加するとこんな感じ。この子は順調に昇進すると大関までは行けます。あれ、行けるかな? …多分いけます(ぉ

ELBが入ることによって、マルチAZ体制が作れますので、可用性もそこそこしっかりしています。

CloudFrontによりスパイク対策は基本的にはOK。ただし、CloudFrontというのは要するに「キャッシュ」ですので、キャッシュヒット率が悪いコンテンツ *5に対しては逆効果になったりもします。

十両: EC2 + Route53

6jyuryo

アプリに独自ドメインを埋め込むようにして、Route53を使ってみました。Route53を使い始めた時点で、この力士には横綱になる可能性を秘め始めます。っていうか、こうなってるならばさっさと横綱になってしまうと良いです。そうでなくても、最低限、関脇にはなっておきましょう。配信体制を変えてもアプリに影響が出ないのですから。

ただし、レベルアップをしない現状のままの体制は貧弱としか言えません。可用性も怪しい、スパイクにも耐えられない状態です。いきなり横綱ではなく、まずはELBを挟んでみてはいかがでしょうか。次の前頭二枚目をご覧下さい。

前頭二枚目: EC2 + ELB + Route53

7maegashira2

Route53をフロントに置くだけで、横綱の可能性が出て来るのは前述の通り。というわけで、この体制は拡張性抜群。スケールアップ/アウトによるスパイク対応もどうにかなりますし、マルチAZ体制もOK。EC2インスタンス維持コストと、コンテンツ動的追加がネックです。

前頭筆頭: EC2 + ELB + CloudFront + Route53

8maegashira1

前頭二枚目に、CloudFrontを噛ましたパターンですね。二枚目よりも配信パフォーマンスが良くなります。

小結: S3

9komusubi

やっと出て来ました、S3。そうなんですよ、EC2要らないんですよ、静的なんですから。コンテンツファイルはS3のバケットに置いておき、publicからアクセスできるように設定する。ただこれだけです。EC2が不要になったのでコストは最安です。S3は何もしなくても冗長化が行われますので、可用性も万全と言って良いでしょう。スパイクで落ちてしまうことも無いでしょう。

ただし、S3は配信パフォーマンスが良いとは言えませんので、ダウンロードが遅い、という悩みはつきまとう可能性があります。また、ホスト名がアプリにハードコーディングされていますので、昇進ができません。

関脇: S3 + Route53

10sekiwake

さて、これが関脇。Route53を介して独自ドメイン名がアプリにハードコーディングされていますので、横綱昇進もあります。ただし、配信パフォーマンスは小結と変わりありません。

大関: S3 + CloudFront

11ozeki

では配信パフォーマンス改善のため、小結にCloudFrontをかぶせてみましょう、というのがコレ。ただし、やはりCloudFrontのDNS名がハードコーディングされていますので、これ以上の昇進が望めません。大関なのに、横綱にはなれないのです。

まとめ

それでは、あらためて横綱を見てみましょう。

1yokozuna

こうして見てみると、立派じゃないですか? Route53を介しているので、アプリに書かれているのは独自ドメイン。CloudFront配信なのでパフォーマンスは最高でスパイクも問題なし、ベースはS3なので可用性も問題なし、コストも安いです。非の打ち所がありませんね。これぞ横綱。あなたのシステムも、是非横綱を目指してください。

スケ 柔軟 可用 パフ コス SSL
序の口: EC2の自動IP × × × × × × ※1
序二段: EC2 + EIP × × × × ※2
三段目: EC2 + ELB × × ※1
幕下: EC2 + ELB + CloudFront × ◯ ※3
十両: EC2 + Route53 × × × ◎ ※4
前頭二枚目: EC2 + ELB + Route53 × ◎ ※5
前頭筆頭: EC2 + ELB + CloudFront + Route53 × ◎ ※6
小結: S3 △ ※7
関脇: S3 + Route53 ×
大関: S3 + CloudFront ◯ ※3
横綱: S3 + CloudFront + Route53 ◎ ※8 ◎ ※6
  • ※1 原理的には可能だが、amazonaws.comの証明書が手に入れられない。
  • ※2 IPアドレスによるアクセスなので、SSL証明書が無効。
  • ※3 cloudfront.netの証明書がAmazonから提供されている。
  • ※4 Apacheに独自ドメインの証明書をデプロイする。
  • ※5 ELBに独自ドメインの証明書をデプロイする。
  • ※6 CloudFrontに独自ドメインの証明書をデプロイする。
  • ※7 Amazon提供のS3ドメインの証明書が利用できる。ただしstatic web site hostingでは不可。
  • ※8 SSLを利用する場合は、証明書を設定している期間に渡って、証明書1通につき600USD/月の追加費用がかかります。

まとめると、ポイントはたった3つ。

  • アプリ内に、AWSから与えられたDNS名やIPアドレスをハードコーディングしない。必ず、独自ドメイン名を書き込むようにして、DNSによる調整の余地を残しておくこと。
  • 静的コンテンツはS3に配備すること。複数のEC2間でNFS共有する、等のアーキテクチャは避けましょう。
  • S3からの直接配信は、さほどパフォーマンスが良くありません。CloudFrontでパフォーマンスを確保しましょう。ただし、キャッシュヒット率の想定が低い場合は要検討。

脚注

  1. といっても横綱状態なので敢えてランクを下げる必要もないとは思うのですが…。
  2. EC2-Classicを起動すると自動的に割り当てられるグローバルIPに対応するホスト名。ex. ec2-XX-XX-XX-XX.ap-northeast-1.compute.amazonaws.com
  3. みなさんだって、サーバのミドルウェアをアップデートしなかったり…するでしょう?
  4. この体制だけではなく、以下でご紹介するELBを含むパターン全て。
  5. コンテンツが無数にあり、一部のコンテンツにアクセスが偏るわけではなく、まんべんなくアクセスされるようなもの。