appengineでアプリケーションを作ってみて注意点・思った事

Google Code Jamに提出されたソースを閲覧するCodejam Source Viewerを作ったときに感じたappengineでアプリケーションを作る際の注意点をメモ.

  • データストア編
    • アップロードできる静的ファイルは最大3000個まで。
    • ローカルにプロキシを置いてクロスサイトAjaxを使うことでストレージを節約すると、今度はネットワークのQuotaを圧迫→ 結局、Yahoo Query LanguageによるクロスドメインAjaxソースコードをダウンロードすることにした。時間当たりのリクエスト数に制限がある.
    • CPU TimeのQuotaがかなりきつい。ちょっとデータストアをいじったり重い処理をすると、すぐに上限に達してしまう。他のQuotaが全然つかわれずCPU Quotaだけがたくさん消費されることもしばしば
    • データストア全件に対する操作が非常に高価なコスト: CPU Quotaがどんどん消費される. 気軽にプロパティの更新とかやるとすぐにQuotaが溢れる
    • データの更新にdb.Model.putを使用すると非常に遅い(数千件で1時間とかザラ)ので、バッチで処理できるdb.putを使うべき. さらに、db.putはエラー時にロールバックしないのでrun_in_transactionの中で実行するべき。処理中にQuotaが溢れて切断とか良くあること
    • バッチでも500件毎にしかデータを登録・削除できないので、全件に対する変更操作はSQLと比べかなり面倒。SQLならorder byしてカーソルで1件づつ取り出すだけのロジックでも、GQLだと操作対象が1000を超えるとModelクラスの__key__プロパティを使ったパジネーションが必要になる.当然SQLのように一行では終わらないのでJavaなりPythonでデータストアを操作するコードを書くことになる
    • GQLのクエリパラメータは型を動的に判定する ⇒ 数値フィールドに文字列を入れてしまうなどのエラーに気をつける
    • パラメータつきのGQLクエリにunicodeを渡すと死ぬ -- repr()でクエリに展開しているのか、文字列リテラルの頭に文字uがくっついてエラーになる *パラメータのあるクエリに二つ以上のunicodeで渡すとエラーになるっぽい?
    • あるコンテストのaccept状況を1問題1ビットでまとめて一つの数値で表現しようとした → 関係演算子しか使えないので、正規化せざるをえない場合がある
    • 速度的な問題で非正規化して格納すると、使えるデータ領域が思ったより少なくなる。また、マスタのコードなどを更新する際に必然的に更新対象行が多くなるので、対象となるすべての行を更新するのもコストがかかる
    • GQLの制限がきつい
      • selectのみ、where句で使えるのはANDと関係演算子のみ / like 不能 / 集計関数 不能 / OR 不能 (代替のINは複数クエリを発行する重い処理) *1
      • 1000件を超えると工夫しないとcountもできない *2。全件取得のコストが高く集計関数も無いため、ランキング、パジネータの実装が難しい
      • GQLクエリにモデルに存在しないプロパティを指定しても実行環境側で警告が出ないので、エラーの原因が分からない場合はフィールド名をtypoしてないかチェック
  • アプリケーション設計の指針
    • CPU Quotaがきついのでできるだけ多くの処理をクライアントにやらせる
      • キャッシュ
      • WebStorageの活用
      • html整形
      • クロスサイトAjax
      • その他処理
    • データストアアクセスを減らす
      • Memcache API
      • トップページに表示されるコンテンツなど、頻繁につかうjsonファイルなどは予め静的に作成するか、cronでバッチ処理で作成する

思ったこと:ポータブルって大事

たとえば普段はクラウドは利用せずに、特定の季節でだけオンデマンドで処理能力を増強したいというようなニーズが考えられるけれど、Google App Engine向けに書かれたアプリケーションは他のプラットフォームで動作しない、アプリケーションがGoogleのプラットフォームにロックインされている。App Engineでのプログラミングのクセを考えると、「他のプラットフォームへ、あるいは他のプラットフォームからのポーティングのコストが少ない」というのもクラウドアプリケーションのプラットフォームに大切かもしれない。現状、そういう状況が予想される場合はAmazon EC2での利用を想定してアプリケーションを組むべきなんだろう。Azureもあるか。appengineでアプリケーションを書くまでは、データストアとRDBMSにこれほど違いがあるとは思わなかった。

気になる

appengine 1.5からGo言語がサポートされた。
Go and Google App Engine
Java/Pythonで書かれた同等のアプリケーションと比べて、Goで書かれたアプリケーションが実行速度やCPU Quotaの制限にどの程度違いがあるか気になる。

参照したサイト群

公式ドキュメント
App Engine上で順位・平均・中央値等を計算するライブラリを作る
こういうのかっこいいなぁ。
Java PaaS の比較
>Google のエンジニアたちは、BigTable でのデータ・クエリーに対する応答時間を決定する唯一の要因は、結果として返されるデータ・セットのサイズだけであると断言
10 things you (probably) didn't know about App Engine
Google App Engine / Python 上での開発で最初から知ってればよかった、ってことをいくつか
エントリ中で紹介されているもの。これは未読だがあとで読む.集計のライブラリっぽい
Google Code Jam's Ranking Library Released
GAEでPythonを始めるときに知りたい4つのまとめ
Google App Engine + app-engine-patchでCPU時間を短縮する
Google App Engineでアプリを高速化する3つのtips
GAEのDatastoreのエントリ削除していたらOver Quotaになった…
Google App EngineでGo言語使って「おうっふー」動かしてみた。
Google App Engine でスケールするwebアプリを書く
【Google App Engine】 すごいのはGDriveより全文検索でしょ!?
Google App Engineでセッションを使う
Google App Engineでよくある質問
GAEの設計指針めも
Google App Engineのランキング問題
Google App Engine上のベスト・プラクティス、その1: Datastore
appengine事例
Open for Questions http://www.whitehouse.gov/OpenForQuestions/
Promeets!
Google Moderator
Google 未来を選ぼう 衆院選 2009
研修会社の横浜YMCA:研修期間に突発的にアクセスがくる.繁忙時に対応
mixiクリスマスというイベントをやった事例
Instagram連携 女の子の顔

*1:"注: IN と != の各演算子は、背後で複数のクエリを使用します。" https://code.google.com/intl/ja/appengine/docs/python/datastore/gqlreference.html

*2:"注: count() の戻り値は最大 1000 です。クエリ条件に合う実際のエンティティ数が最大数を超えると、count() は1000 を返します。" https://code.google.com/intl/ja/appengine/docs/python/datastore/gqlqueryclass.html#GqlQuery