2011-12-31

翻訳: Google App Engine で、アプリケーションの応答をよくする 15 の方法

大規模ウェブサービスのプラクティスを紹介している、High Scalability の記事「15 Ways To Make Your Application Feel More Responsive Under Google App Engine」を訳しました。


記事は Java 前提で、私は Python で Google App Engine を使っているのですが、それでも面白いなと思ったので、有効な方法は使っていこうとしています。ついでなので翻訳したものを残しておくことにしました。




軽量な査定用フィードバックサービスを提供している Small Improvements が、Performance issues on GAE, and how we resolved them という素晴らしい記事を書いている。どのようにして、ほとんどのリクエストを 300ms から 800ms でさばき、memcache が効いていなくても2秒、速いページなら150ms 程度でさばけるようになったかの事例になっている。全体として、ものすごく速くしているわけではないけれど、PaaS として GAE が気に入っているなら、検討すべき内容だろう。

パフォーマンスが悪いときに、できることが限られているというのが、PaaS のやっかいなところだ。でも、Small Improvements の人たちは賢くかつ辛抱強く改良をして、詳細な方法とその結果を提供してくれている。アドバイスはGAE に特化したいるけれど、別の状況にも当てはまるだろう。以下に、彼らが実施した、パフォーマンスの小さな向上(small improvemens) の15の方法をあげる。

  1. App Engine が遅い日もある、と知る。 App Engine はパフォーマンスが悪い日がある。設計段階で、潜在的にレイテンシが変化することを考慮しておく必要がある。常にベストな状況であることを想定しないこと。
  2. クエリよりも GET する。 Datastore から、ID で直接取得するのは 250ms 。クエリするのには 800ms かかる。
  3. GET のバッチと、スレッドローカルキャッシュを組み合わせる。キーごとに個別にGETせず、ひとつのバッチにまとめて GETする。結果を HashMap に保存しておいてレンダリングに使う。モジュール化したアプリケーションでは、内部状態の小さな断片を、引き回すのは避けたいだろうから、ThreadLocal に置いておき、いつでも各モジュールからアクセスできるようにする。
  4. クエリの結果は Memcache に保存する。 appstats ツールを使ってどのクエリが、キャッシュするに値するほど使われているからを見つけ出す。
  5. ログイン前にmemcache を温める。 ユーザが完全にログインするより前に Ajax を発行して、データをキャッシュしておく。
  6. ログイン後に memcache を温める。 ユーザがログインしたら、次に読み出しそうな5ページをキャッシュしておく。
  7. 救いようがないほど遅いときには、つなぎのページを表示する。 最初のクエリの時間を測り、もしも遅ければより速いページへ遷移させる。そのページが閲覧されている間に、元のページをキャッシュする。
  8. memcache を使えないといは、非同期に読み出すことで、行儀よくしょぼくする。クエリが遅いなら、その場では全情報をレンダリングしない。クエリが終わったところから順番に描画する。
  9. アクティブでないときにも再キャッシュ。ユーザがしばらくアクティブでない状態が続いたら、キャッシュが失効しそうなデータを再キャッシュするようなリクエストを、ブラウザから飛ばす。こうすればユーザが戻ってきたときにキャッシュに残っている。
  10. データを非正規化する。「このマネージャの部下は誰か」のような 300ms かかるようなクエリは、結果を予め保存しておき、人同士の関係が変わったときに再計算する。こうすれば GET で結果を取得できるので、速い。
  11. JAR を使う。 これ最強。何千ものクラスがあったら、ロードするのに 400ms はかかる、これはディスクアクセスがあるからだ。すべてのクラスを JAR に入れておけば、ロード時間が飛躍的に向上する。
  12. ウォームアップリクエスト。 できるかぎり GAE の warmup 機能を使う。コードパスを吟味して memcache にデータを書き、主な UI を描画し、鍵(キー)となるクエリを発行し、ログインをシミュレートし、時刻の計算をする。こういう処理は VM とデータをウォームアップする。
  13. 書込は後回しにする。 時間がかかったり、たくさんのクエリを発行した後は、書込処理をタスクキューにいれる。
  14. 非同期でメールする。 メール送信はタスクキューから行う。
  15. 非同期でクエリする。複数のクエリを並列に実行する。