現在のクライアントでアクセス数の多いサイトが会員制サイトに移行しようとしているんだけどと相談されたので、基本的な対策をドラクエを例に説明します。
サイトが落ちる=パーティ全滅
Webサイトのアクセスが増えてくると、サイトに503エラーが頻発して落ちてしまいます。ECなのか広告収益のサイトなのかはともかく、落ちている間は収益を失います(=機会損失)。Amazonはサイトの表示速度が0.1秒遅れると利益が1%ぐらい落ちるそうなので、基本的には「サイトのパフォーマンスが悪いと利益が落ちる」のであり、「負荷が高過ぎてサイトが落ちちゃった」というのはその中でも最悪の出来事と考えた方がいいです。
ものすごく大量の敵とエンカウントしたのに、全滅して経験値入らなかったという状況ですね。基本的に一つ一つのアクセスは敵からの攻撃だと思ってください。
理想としては「無限のアクセスに対し0秒で応えること」ですが、そんなのは無理なので現実的な解を見つける必要があります。この事態に対応するために取れるアプローチは基本的に2つです。
サーバを増強する
サーバを増強してパワーアップすれば耐えられます。まず簡単なのは「高性能なサーバに変える」です。これはドラクエでいうところのヒットポイントを上げるですね。ヒットポイントが沢山あれば死ぬまでに時間がかかります。
もう一つの方法は水平分散、つまりサーバを複数台構成にすること。一台で運用していた場合はWebサーバとDBサーバを分けたり、DBサーバを複数台にレプリケーションしたりなどが考えられます。ドラクエでいうところのパーティの人数を増やすですね。
コモディティ(ありふれた商品)化したものを組み合せた方が全体のコストは安くなるので、そこそこ手頃なサーバを複数台組み合せるのが普通です。Amazon EC2だとインスタンスを増やせるので、現実的な価格帯のインスタンスを増やしていけばいいんじゃないでしょうか。ドラクエでいうと、HP999の勇者一人よりHP120の武闘家5人の方が全滅しにくいという感じでしょうか。
負荷を減らす
もう一つのアプローチとしては「負荷を減らす」ことです。この方法はたくさんありますが、重要なのを2つだけ書きます。
1. ファイルへのアクセスの回数を減らす
Apacheのmod_expiresなどがそうなのですが、そもそもサイトにアクセスする回数を減らすと負荷が減ります。4kbのロゴ画像などを考えると、UUが月間80万人で、一人当たり平均PVが月間40だとすると、月間で4kb * 80万人 * 40PV = 12.8GBになるわけです。たかが4kbの画像でもこんなにいっちゃうんですね。ロゴ画像のように滅多に変わらない画像の場合は「一回取りにきたらもう一年ぐらい取りにこないでブラウザのキャッシュ使ってね」とすることで負荷を下げられます。上の場合でいえば月間12.8GBを3.2GBに下げられるんですね。ドラクエでいうところのマヌーサです。攻撃が当たる回数を減らすんですね。
また、一つ一つのファイルサイズを減らすという方法もあります。mod_deflateでgzip出力とか、/pakcer/でJS圧縮とか、そういう手法です。これはドラクエでいうところのフバーハですね。
CSSスプライトのように、ルックアップの回数を減らすというのも有効です。合計6kbの画像を出力する方が1kb*6回より負荷が少ないんですね。これはドラクエでいうところの……なんでしょうね。自分がはぐれメタルだったらと考える方がいいかもしれません。普通の攻撃一回ではぐれメタルは死にませんが、しょぼい攻撃6回だと死んじゃうかもしれません。
2. データベースへのアクセス回数を減らす
どのプログラミング言語を使っているにせよ、ボトルネックになりやすいのはデータベースI/Oです。データベースへのアクセス回数を減らすことでこれは解決します。
めんどくさいやり方
一つ一つのプログラミングを見ていって、そこをキャッシングするという手法です。キャッシングの手法としてはmemcachedとかが有名です。ザオリクの使える賢者が死んだらやばいからスカラかけとくみたいな感じですね。
おおざっぱなやり方
ページ全部キャッシングしちゃうという方法ですね。PHPやRubyといったサーバサイドスクリプトすら起動させることなくページを返します。これはアストロンです。WordPressでいうところのWP-Super Cacheとか、Nginxでリバースプロキシとかはこれに当たります。この手法はかなり強力で、月間数千万PVというオーダーでもさばくことができますが、ログインしてユーザーに応じているコンテンツを出している場合は使えないんですね。俗にいう「こんにちは◯◯さん問題」です。
どこかで見たようなコンテンツを大量生産してPV稼いで広告収入みたいなサイトを運営しているならアストロンかけとけばOKです。すいません、ちょっと呪いにかかって毒吐いちゃいました。ともかく、個々のユーザーに対して何かを提供したい場合はその部分はキャッシュできません。最近のトレンドはNginx + リバースプロキシを基本にしてユーザー固有のコンテンツをAjax読み込みという感じでしょうか。パーティの3人にアストロンかけておいて、1人にはスカラかけつつガンガンいこうぜですね。
ものすごい負荷の高い会員制サイトというのは現在のWebサービスの花形(Facebook、Twitterなど)なので、あとはエンジニアががんばるしかないですね。
というわけで、ドラクエに喩えてみましたが、わかりやすかったでしょうか。負荷が高いということはそれなりに収益を上げていると思うので、それなりにコストをかけつつがんばってください。サービス設計がよっぽどまずくない限り、負荷が高くても解決策はあるはずなので、答えは必ず見つかります。
[429] [429] Client error: `POST https://webservices.amazon.co.jp/paapi5/getitems` resulted in a `429 Too Many Requests` response: {"__type":"com.amazon.paapi5#TooManyRequestsException","Errors":[{"Code":"TooManyRequests","Message":"The request was de (truncated...)