2012年1月15日日曜日

CoCafeでのGoogle App Engine側の工夫

年末に @aqubiCoCAFE というアプリケーションをリリースしました。喫茶店のWiFi状況やらなんやらを共有するiPhone用のアプリケーションです(Android版も作ってます)。

このアプリケーションでは Google Places APIとGoogle App Engineを使っていて、Google App Engine側では以下のような工夫をしてます。

Datastore(HRD)

  • 地図のZoomに合わせた範囲検索をEqualityフィルタで実現するため、店の位置情報はGeoHashの先頭4文字,先頭5文字,先頭6文字,先頭7文字...とリストプロパティに保持→前方一致検索を使わずに済むので、別の条件で同時にInequeality Filterを使うこともできる。
  • 利用ユーザ等の統計をとるためのアクセスログ的なデータは、必要な情報を全てKeyに詰め込んでいる→ Datastore Write Operationsの節約

Task Queue

  • APIごとのアクセスカウンタは、リクエストを受け取ったときにはPull modeのTask QueueにTaskを追加。定期的にそれをPullして集計し、Datastoreに反映→ Datastore Write Operationsの節約、更新の衝突の心配もせずに済む

OAuth Provider

  • App EngineのOAuth Providerを使用したのでOAuth Provider的なコードはほぼ書かずに済んだ

開発にかかった時間の殆どがクライアント側の実装と、操作性の調整です。Google App Engineだとサーバ側の実装はDBのコネクションがどーたらとか全然関係ないし、自動テストも簡単に実装できるし、全ての自動テストを実行しても大概数秒で実行できるし、ミドルウェアの設定も保守も必要ないし、運用も手間がかからないし、アプリケーションに集中したい人にはラクで良いです。

2012年1月13日金曜日

Slim3+Cross Group TransactionをUnit Testで使う #gaeja

昨年末から何度か「Slim3でCross Group Transaction(所謂XG)をUnit Testで使う時どうするの」的な話を見かけつつ、反応できていなかったので書いておきます。

まず「UnitTest環境でHRDを有効にする」「(Slim3で)XGを使う」のふたつに分けて考える必要があります。

UnitTest環境でHRDを有効にする

Slim3は1.0.15くらいからGoogle App Engine SDKが提供するUnitTestの仕組みを併用できるようになっています。mavenを使っている方は、最新のslim3-archetype-pluginを使ってプロジェクトを生成した場合にappengine-testing等のモジュールが依存に追加されている事に気づいた人もおられるんじゃないでしょうか。

Slim3のAppEngineTestCaseを継承したテストクラスの場合は、SDKが提供するUnit Testの仕組みを併用して、setUp()/tearDown()を次のようにするとHRDが有効になります。

LocalServiceTestHelper helper;


@Override
public void setUp() throws Exception {
  LocalDatastoreServiceTestConfig dsConfig =
    new LocalDatastoreServiceTestConfig()
      .setDefaultHighRepJobPolicyUnappliedJobPercentage(0.01f);
  helper = new LocalServiceTestHelper(dsConfig);
  helper.setUp();
  super.setUp();
}

@Override
public void tearDown() throws Exception {
  super.tearDown();
  helper.tearDown();
}

Slim3でXGを有効にする

Transactionオブジェクトの構築方法によります。

Slim3のDatastore.beginTransaction()を使ってTransactionオブジェクトを作っている場合は、システムプロパティにslim3.useXGTX=trueが指定されている必要があります。Server環境(Productionサーバ、開発サーバ)で起動している場合はシステムプロパティはappengine-web.xmlでそれを指定すれば良いですが、Unit Testの際にはappengine-web.xmlが読み込まれませんので、setUp()の際にSystem.setProperty("slim3.useXGTX", "true");とする必要があります。

Slim3のDatastore.beginTransaction()を使わず、Low Level APIを使ってDatastoreServiceFactory.getDatastoreService().beginTransaction(TransactionOptions.Builder.withXG(true));としてTransactionオブジェクトを作っている場合はSlim3のシステムプロパティを気にする必要はありません。Slim3が使用するTransactionオブジェクトはLow Level APIで使用するTransactionオブジェクトと同じクラスですので、Low Level APIとの併用も可能です。

私としては、slim3.useXGTX=trueを指定せずSlim3のXGは使えなくしておき、XGを使うときはLow Level APIを使ってTransactionオブジェクトを作成する方が好みです。XGを使用している事がコードから明確に見て取れるという点が嬉しいです。

2011年9月21日水曜日

Google+ Hangout APIが公開されています

Gadgetとして作成するようで、Hangouts画面にアプリケーションが埋め込まれる、といった形で実行されます。

手っ取り早い試し方

  1. Google API ConsoleGoogle+ Hangouts APIONにする
  2. API Consoleの左側のメニューにあるHangoutsをクリックすると、Gadget URLを入力するテキストボックスが配置されたページが開きます。
  3. 本来ならWriting Hangout Apps - Google+ Platform — Google Developersを確認してガジェットのコード(XML)を書いて外から見える場所(Google CodeとかApp Engineとか)に配置する必要があるのですが、サンプルがあるので手っ取り早くそれを使いましょう。
  4. https://google-plus-hangout-samples.googlecode.com/hg/samples/yes-no-maybe/ggs/yesnomaybe.xmlを入力し、saveをクリックします。
  5. Gadget URLが正しく読み込まれると、Enter a hangout!というリンクが表示されるのでクリックすると、ガジェットが実行されますので入室しましょう。入室すると左下の「Chat」の横に「App」があるので、クリックします。すると、Waveでよく使っていた Yes/No/Maybe のVoteアプリが起動しました!

  6. 右上にある「Manage Apps」と書かれたツールバーの「Get My App」ボタンをクリックすると、API Consoleに登録されているプロジェクトからアプリをLoadすることができます。同時に複数のアプリをLoadしたらどーなる?と試して見ましたが、一個しか読み込めないようです。

今のところは参加者のアカウント一覧を取得したり、現在のアクティブスピーカー(発言中のアカウント)を取得したり、デバイスの状況(マイクあるの?とか)を取得したり、チャットの領域を表示・非表示するなどの制御ができるようです。Gadgetのコンテナを実装してGadgetでアプリを作るプラットフォームを提供してくるというのは予測済みでしたが、まさかHangouts画面をコンテナにしてくるとは思ってませんでした。あんまり使う気はないけれど、良い意味で裏切られて面白いです。

P.S. Google様、リアルタイムストリームを取得するAPIを心待ちにしているのですが、できればPubsubhubbub経由以外で、デスクトップクライアントから使えるようにお願いします。どーしてもPubsubhubbub経由になるなら、まだ見ぬFeed API V2(Google I/O 2010で発表されてましたね!まだ待ってます!)と共にリリースしてくださいませんかお願いします。

2011年9月16日金曜日

とうとう公式のGoogle+ APIが公開された…気がしたがそうでもない

Getting Started on the Google+ API - Google+ Platform Blog

この記事のタイトルを見て喜んだ人もたくさんいるんじゃないでしょか?承認はOAuth2だし!
しかし残念。まだDiscovery APIにも対応しておらず、そのためかAPI Explorer上でも使えません。Buzz APIでいうscope:publicしか対応しておらず、consumption/comments/likedが使えません。がっかり。Buzz APIでのscopeはcollectionというパラメタに変わるようです。さらに、likedはplusedとなるのかもしれませんね。まぁ細かいことはどうでもいいです。

  • プロフィール情報の取得
  • アクティビティ(投稿)のリストの取得
  • アクティビティ(投稿)の取得

たったこれだけしかできません。アクティビティのリストも「公開」のもののみ。どれも、これまでだってスクレイプすりゃとっくに取得できてたもんです、がっかり。

  1. API ConsoleでGoogle+ APIをONにする。
  2. API Consoleの左のタブから「API Access」を選択して、「Simple API Access」欄の「API Key」をコピペする。
  3. プロフィール情報の取得であれば https://www.googleapis.com/plus/v1/people/115271879735982073394?key={YOUR_API_KEY}
  4. アクティビティ(投稿)のリストの取得であれば https://www.googleapis.com/plus/v1/people/115271879735982073394/activities/public?key={YOUR_API_KEY}
  5. アクティビティ(投稿)の取得であれば https://www.googleapis.com/plus/v1/activities/z12aejnbcwekizmi304cgnzbcwq0e5cxnag?key={YOUR_API_KEY}

上記が使用例です。115271879735982073394ってのは私shin1ogawaのIDです。{YOUR_API_KEY}には、手順中でコピーするもので置き換えてください。

…これくらいしかやることがありません、がっかり…でもG+API担当者の方、重要な第一歩をありがとうございます。お疲れ様でした。

APIに関する公式ページの http://developers.google.com/+/api の変更を監視開始しましたので、これからガンガン機能追加されて忙しくなんだと思います。

2011年9月10日土曜日

Google App Engineの新料金体系に向けた準備 #gaeja

新料金体系について公開されている情報

これらの情報の中で、特別重要だなーと思うのは以下の点です。

  • CPU時間ではなくインスタンス起動時間で課金されることになる。無料枠は24時間…ではなく28時間(上記最後の記事で出ている話で、まだ28時間無料となった状況での課金結果は確認できてません)。
  • Datastore操作APIが高くなる
  • いくつかのAPIは無料になる
  • 管理コンソールの「Billing History」で、新料金に換算した時の価格を確認できる
  • 管理コンソールの「Max Idle Instances」「Min Pending Latency」のふたつの設定を触ることで、無駄なインスタンスをできるだけ立ち上げず、スケールアウトしづらくするようスケジューラの動作を制御できる
  • リクエストを並行処理する設定にすると、複数リクエストを同時にひとつのインスタンスで扱える(GAE/Javaでは現状でも既に可能、GAE/Pythonは将来のPython2.7から可能)

簡単なチューニング結果の紹介

以下は私のアプリケーションで、Lingrの特定のroomへの発言に対してbotとして動きつつ、5分に一回Redmineに対してSVNの更新チェックをキックする、といったbot系のアプリケーションの課金額です。チューニングと言っても、プログラムは一切さわらず、管理コンソールから「Max Instances=1、Min Pending Latency=15s」という設定を行うだけで、その設定を行う前後の比較です。

設定前後のインスタンス数グラフ

二日前に何か設定が変わった?という事が明らかにわかるグラフですが、インスタンス数の平均がガクッと減っています。

設定前の課金額

左が現行の料金体系で、余裕で無料に収まっています。右が新料金体系で、インスタンス時間が103時間を超えていて、$3.3/日となり、月7000-8000円程度になるようです。こういうアプリをたくさん運営している場合は、ちょっと個人にはツライ金額です。

設定後の課金額

先のスクリーンショットと同じく、左が現行の料金体系で、余裕で無料に収まっています。右が新料金体系ですがインスタンス時間が27時間程度に収まっていて、$0.3/日となり、月700-800円程度にまでおさえれそうです。さらに、これはインスタンス時間の無料枠を24時間とした時の金額なので、実際には28時間無料で計算すると月400円程度になります(優良枠で利用する場合は実際には最低$9なので、それより下にしても変わらない)。さらに、このアプリはMemcacheを全く使っていなかったり設計も適当な手抜きアプリなので、少しチューニングすればデータストア操作も無料枠に収まり、結局無料枠で稼働できると思われます。

それでもまだ無料枠に収まらない

シンプルなアプリなんだけど、無料枠が28時間でもギリギリ超えてしまうよ…といった、「無料に抑える」が目的の時に、一部の処理を「Backends」の9時間の無料枠に振ってしまおう、というのが「App Engine のリソース管理 - TaskQueue の設定 - Kay's daddy」の記事に書かれているチューニング方法です。課金額を抑える目的でないとしても、Task QueueをBackendsで処理させるという手法は重要ですので、Backendsという機能を知らなかった方は見ておくと良いです。

大規模なアプリなので無料枠を目指すわけではないがもっと安くry、といった場合は……主にDatastore操作が高くなると思いますが、そのあたりのチューニングを進めるしかありません。Queryの実行に対して、QueryによるKeyのみのフェッチは価格が1/7、という点に注目すると面白いかもしれませんね。

とはいえ、いきなり設計を変えるわけにも行かないし、これまでは正式版じゃなかったから仕方ない…と簡単に諦められるもんではありません。ボリュームディスカウントの導入とか、もう少しくらい値下げが無いものか?とか色々期待しましょう。提案等がある方は中の人に直接メールをしてみると良いと思います。

新料金体系の導入についての感想

これまでは、Google App Engineというと、「価格」「(自動スケールアウトも含めて)運用の手間が無い」のふたつの特徴が大きく言われていました。これが、「価格」については魅力ががつーんと低くなりますね。でも共有地の悲劇みたいな事がずっと起こってパフォーマンスが出にくい時期もありました(あっと言う間にSpin downしちゃう→毎分Cronで叩き続けてちょっとでも確保しよう→余計にSpinDownしやすくなるとか)し、負荷をかけるばかりのアプリケーションをある程度追い出すという結果になるなら、丁度良いバランスの設定かも?と思います。特に現在のGoogle App Engineのデフォルトの設定では「パフォーマンス優先」となっていて、適切に設定を行わない限りはシンプルなTwitterbotアプリでも簡単に「毎月一万円」くらいに達してしまうので、設定や開発で工夫をしようとしない人は利用をやめることになるのでしょう。

私はというと、OSやらミドルウェアのインストール・設定・パッチ適用などのメンテナンス…といった「運用の手間」に関しては完全に排除したい(そもそも知識も興味も無い)人なので、値上げがあってもGoogle App Engine以外の選択肢は今のとこあまり考えていません。上述しませんでしたが、Google App Engineが提供するテスタビリティが高い開発環境、優秀なApp Engine専用フレームワークの存在、といった状況もアプリケーションの設計実装に集中したい私には重要です。そんなワケで新料金体系については「値上げか仕方ないなー、でもお金取るんだからこれまでよりももっとしっかり運用、情報公開して欲しいですね」という感想です。確実に利用者は減るでしょうから、その点だけは「寂しいな」と思いますけどね。

また、ポータビリティが極端に低いGoogle App Engineで今回のような事件が起こることで、今後のPaaSの選定基準でのポータビリティの重要度が増したりするのかな?といった点も興味深いです。

追記

一定の時間間隔でURLFetchして単純な処理を…といった程度であれば、Google App EngineではなくてGoogle Apps Scriptでも可能ですよ。