Google App Engine入門:実践編
2010.03.04
今週に入って、Tiny Message に続く二つ目の Google App Engine ベースのサービスをリリースした。3日ぐらいで試験的に作った Tiny Message とは異なり、今回のものは、丸二ヶ月間寝る間も惜しんで作った力作である。
米国向けのサービスな上に招待制のSNSなので、ここではサービスそのものは公開しないが、いくつかこだわって作った部分があるので、それについて語ってみようかと思う。
1. 対象となるユーザーの絞り込み
FacebookやTwitterのような巨人が存在している中で、それにまっこうから対抗するようなソシアル・ネットワーク・サービスを作ったところで無謀なだけである。そこで、逆に対象にするユーザー層を究極にまで絞り込んで、彼らのライススタイルに徹底的にマッチしたサービスを作ることにより差別化をはかる、という戦略を選択。対象は「LAに住む20〜30代の社交的な人たち」である。年齢層だけでなく、地域とライフスタイルを限定することにより、FacebookやTwitterよりも密度の濃いコミュニティを作ることを目指す。
2. 招待制
上に書いたように、数よりも密度が重要なので、既存のメンバーから招待状をもらわないかぎりメンバーになれない招待制にした。その上、メンバー同士の会話は一切外には見えない(つまりググっても見つからない)クローズなものにした。その部分に関しては、mixiと似ている。当然、こんなアプローチを取れば急速なユーザーの増加は望めないが、あえて初期のユーザーの数を抑えることにより、ユーザー一人一人の行動を丁寧に観察して、彼らが必要とするものをキチンと提供して行くことにより、利用率・定着度の高いサービスを目指す。
3. 100% AJAX(AJAX時代のMVC)
サーチエンジンがたどりつけないクローズなサービスにしたということは、クロールしやすいサイトにする必要が全くないということである。そのことはすなわち、「AJAX使い放題」を意味する。そこでアーキテクチャは徹底的にAJAX化をし、ModelはApp Engine上のPython、Viewはstatic server上に置かれた静的ファイル、Controllerは100%JavaScriptという設計にした(下の図参照)。
ユーザーに何か表示する時は、まずはAJAXでサーバーのAPIをたたいてデータをJSONの形で取得し、それとstatic serverから取得したHTMLテンプレートをJavaScriptで実装したテンプレート・エンジンを使って合成してから表示する、という仕組み。AJAXとDOMの操作のためにjQueryを使っているが、その上の7つのプラグインはすべて自作した(時間ができたら公開する予定)。
コードのサイズは、Modelを実装しているPythonが2200行、Controllerを実装しているJavaScriptが5500行、HTMLテンプレートが1800行、というバランスだ。
4. クライアント・サイドJOIN
App EngineがJOINをサポートしていないことは、リレーショナル・データベースに慣れた人たちからしばしば批判される点だが、このアプリでは、JOINに相当することはすべてクライアント側でしているのでその必要性すら感じない。もちろん、ユーザーをまたせないように非同期でデータを取得して表示する仕組みなど、いくつかの工夫はほどこしてある。ちなみに、クライアント側でJOINをすると、サーバー側のキャッシュのヒット率が上がるというとても重要な利点があるのだが、これに関してはここに書くと長くなるので、別途詳しく解説しようかと思う。
5. キャッシュの最大限の利用
これに関しても、別エントリーで詳しく書くつもりだが、サーバー側の負担をできるだけ軽くするために、いくつかのレイヤーのキャッシュを積極的に使用している(下の図参照)。サーバー側でPythonのグローバル変数とmemcacheを使っているのはもちろんだが、AJAXで取得するJSONも、JavaScript上にオブジェクトとしてキャッシュしたり、ブラウザーのキャッシュをサーバー側からきめ細かにコントロールすることによりHTTPリクエストそのものを減らす工夫をしている。
6. サーバー・プッシュ
チャットや友達のオンライン状態の表示の実装ためにサーバーからプッシュする仕組みを作った。App Engine上ではCometの仕組みは使えないので、pollingを使って実装しているが、そのたびにデータベースに書込みをしていたのでは負荷が高すぎる。そこで、memcacheを使ってユーザーのオンライン状態を監視するという若干「おきてやぶり」なことをしている(memcacheはキャッシュなので、本来はそんな使い方をするものではない)。とりあえずうまく動いているが、同時にアクセスするユーザーの数が増えた時にmemcacheがどこまでスケールするかは注意深く見ておく必要がある。
この仕組みを使ってさまざまな通知をサーバー側から行っているのだが、その中でも重要なものの一つが、クライアント側のキャッシュをサーバー側からフラッシュする仕組み。クライアント側でキャッシュされているデータに変更が必要な際に、クライアントに向けてキャッシュをクリアするようにサーバーから指示をするのだ。
7. TaskQueueを使った非同期タスク処理
TaskQueueはGoogleにとっても「実験中」という位置づけなので、最初はおそるおそる使っていたが、あまりにも便利なので、その上に非同期タスクマネージャのようなライブラリを作ってさまざまな場所で使っている。たとえばユーザーのエントリーに他のユーザーからコメントが追加された場合、エントリー側にコメントの数をプロパティとして持たせているのだが、ユーザーにとっての見かけの待ち時間を短くするために、その計算はコメントの書込みと同時には行わず、TaskQueueを使って非同期に行っている。それ以外にも、友達のオンライン状態の監視、アクセスログの集計、週一のメール配信など、すべてこの仕組みを使って非同期に行っている。
ユーザー視点としては、どのようなインターフェースで、どのようなサービスなのか、とても気になります・・・!
Posted by: eakas | 2010.03.04 at 04:37
基本的に100%ユーザードリブンで作っているので説明しにくいんですが、イメージとしては、Google Waveを簡略化にして友達と夜遊びの予定を立てやすくしたような感じです。
Posted by: Satoshi | 2010.03.04 at 05:09
時期はずしてますが一点ご質問させてください。
>7. TaskQueueを使った非同期タスク処理
がUIレスポンス改善に効きそうだと感心したので自分でも実装し始めたのですが、
Background work with the deferred library - Google App Engine - Google Code : http://goo.gl/jPBu
と、言うものがある事に気がつきました。
こちらのライブラリの利用は検討されました?
もし検討されていたら独自実装を選択された理由をお聞かせいただければと思います。
Posted by: ryu | 2010.06.21 at 07:14
はじめまして。
記事拝見しました。
「4. クライアント・サイドJOIN」について、別途解説、、とありますが書かれてますでしょうか?
探したのですが見当たらないので…
Posted by: takk | 2010.07.07 at 20:51