ラベル Google App Engine の投稿を表示しています。 すべての投稿を表示
ラベル Google App Engine の投稿を表示しています。 すべての投稿を表示

2012年9月3日月曜日

App Engine Full-text Search API の使いどころ

今年になって Google App Engineに Full-text Search(以下FTS)という機能が追加されています。全文検索機能の事で、日本語にも対応しています。リリース前に私も appengine ja night 20 で紹介をしました。その時にも「日本語検索はおまけ、それ以外の機能が強力」という話をしたのですが、それについて少し具体例を交えて説明をしようと思います。

ログインユーザごとのアクセス権限を参照する処理

RDBでは簡単でも、データストアで苦戦することまちがいなしの要件として、次のような要件がよく出てきます。

  1. 企業向けアプリケーション等で、リソースへのアクセス制御をしたい
  2. リソースに対するアクセス許可リスト(ACL)として、ユーザIDだったり、ユーザを束ねたグループIDだったりを定義する
  3. ログインユーザに対して、リソースの一覧を提供する。もちろん、アクセスできるもののみが一覧表示される。

企業向けアプリケーションではまず必要になる、よくある処理だと思います。ここでは企業向けアプリケーションと書いていますが、例えばTwitterなどの、ユーザ間の関係が発生するアプリケーションでも同じような要件が出てきます。なお、ここでいうグループはディレクトリ的なものではなく、一ユーザが複数のグループに所属できるような関係を想定しています。

データストアで実装する

これをデータストアで実装しようとするとなかなか厄介ですが、大きく分けると「保存時に頑張る」「クエリ時に頑張る」の二種類の方針が考えられます。

後者の方針は早々に破綻する可能性があるため(一覧表示くらいならなんとかなるが、なんらかのフィルタがくっつくと処理に相当無理が出るし、固定の件数でページングするのも難しい)、多くの場合は前者の「保存時に頑張る」方法で次のように実現することになると思います。

  • リソースが保存された時に、それにアクセスできると定義されたグループから、ユーザを展開する
  • 展開したユーザ(リソースにアクセスできるユーザ)分だけ、「ユーザごとにアクセスできるリソース」を作成し、保存する。このエンティティはユーザのIDとリソースのIDを保持します。カインド Readable としましょう。
  • ログインユーザがリソース一覧を表示する場合、Readableに対してクエリを発行します。

独自にインデックス用のエンティティを作るということです。この実装方法ですとアクセスの制限が広いリソース(全社員向け、とか!)が保存された場合、ものすごく大量の Readable エンティティが作成・保存されますし、それ以外に面倒な非同期処理も必要になります。例えば、グループ内のユーザが変更された場合や、ユーザが新たに発生した場合です。しかし、「クエリ時に頑張る」実装よりは、ユーザに対して良いパフォーマンスを提供できるので、保存時に頑張る、を選択することが多いのではないかと思われます。

FTSを利用する

FTSを使うとかなり簡単になります。

  1. リソースが保存された時に、リソースの主キーと、アクセスを許可するグループやユーザのIDを多値フィールドとしてFTSのDocumentに追加して、インデクスさせる。DocumentのIDとしては、リソースの主キーをエンコードした文字列を使用しとくと便利です(FTSにもkeysOnlyなオプションがあるのです)。アクセスを許可するグループやユーザのIDは ACL というフィールド名とします。
  2. 例えばログインユーザが g1 ,g2, g3 というグループに所属している u1 というユーザであれば、FTSで「ACL=u1 or ACL=g1 OR ...」とORでつなぐだけ。ソートやフィルタが必要であれば、それらのフィールドをDocumentに追加しておくと良いです。で、取得したリソースのキーを使って、データストアから必要なリソースをバッチGETすればリソース本体も取得できます。それが面倒なら、Documentの方に必要なフィールドを含めても良いでしょう(そうこうするうちにデータストアが不要になった、となる可能性もるかも)

工夫も何もありません、特にめづらしい実装にも思えませんが、FTSを日本語検索ではない目的で使用するのが強力だ、と言っていたのはこういう処理で使うことを想定していたためです。データストアだけでは実装コストもランニングコストも高くなってしまう処理が、工夫もなく簡単に実現できてしまうのです。グループのメンテナンスが発生した場合の整合性を維持する非同期処理は同じように残ってしまいますが、そこはデータストアに対するメンテナンスよりも軽くなるはずです。

これに日本語検索を加えてもいいです。今のところ、FTSを多用する場合の注意点は次のようなものがあるとおもいます。

  • FTSはまだExperimentalなため、APIのRateと保存容量にLimitが存在する上、利用料金も決まっていません。これらふたつのLimitはGooglerに連絡すれば回避できますが、料金はちょっと心配です。 しかし、独自にインデックス用のエンティティを作って実装している場合はWrite Operationsもかなり大きいので、それら程度であれば、実装のコストが削減できる分FTSの方が良いですね。
  • FTSはまだExperimentalなため、不具合が無いとはいいきれません。
  • クエリに使える文字列は 2000文字が限界です. ひとりのユーザが数百のグループに所属…となると、それにひっかかってしまうかもしれません。それが心配な場合は、ユーザやグループのメールアドレスなど長い文字は使わず、別の短い値に変換して使うと良いでしょう。

まとめ

SDK1.7.0 から Datastore に対してもORによるフィルタが指定できるようになりましたが、その機能ですとカーソルを返せない(実際には複数クエリを並列実行してるだけなので、当たり前ですね)という問題があります。

Cloud SQLを組み合わせればFTSなしでも同じことができますが、テスト環境の手間が多少なりとも増えてしまうのがイヤな人にはデメリットです。が、このあたりは好みによりますね、素直にCloud SQLで慣れたRDBの設計・実装を行うのも実装コストを減らす選択肢のひとつです。Cloud SQLはスケールアウトしないという特徴にも注意が必要かも。一社のみで使うアプリケーションであれば良いですが、複数社に提供する業務アプリケーションであれば、ボトルネックになる可能性があります。

おまけ

肝心の日本語検索ですが、 Google検索 >>> Gmail検索 = FTS > Google Docs検索 といったかんじの性能じゃないかなーと感じました。

2011年5月28日土曜日

#appengine ja night 16( #ajn16 )が開催されました

5/27(金)にappengine ja night #16が開催されました。今回はajn史上最高の女性比率を記録するほど、たくさんの女性に来ていただけまして大変よい雰囲気の中で実施されました。過去の最高記録比400%くらい達成した気がするので、この勢いでいけば次々回あたりには参加者が全員女性という可能性も見えてきました。
今回参加された女性陣の方々で、ちょっとでもappengineやサーバサイドの世界、またはコミュニティそのものに興味が!、とかなんでもいいんで興味を持っていただけた方&楽しんでいただけた方は、是非次回以降も継続しての参加をお願いいたしします。

いつものように@drillbitsさんtogetterにまとめてくれています、ありがとうございます。

@kazunori_279さんがいつものようにUstream配信して下さり、録画もあります

@yanzmさん: GWT+UIBuinderのお話

ajn史上二人目の女性発表者です。今回は集まり具合が半端ない(いつもは開始時間では半分ちょっとくらいなのに今回は開始時間で相当埋まった)状況だったのですが、あんざいさんのおかげなのでしょうね。
個人的には GWT は大昔に一度調査したきりでそれ以降使っていませんが、最近の情報を(自分で調査すること無く)知ることができるならこれは美味しい機会だという雰囲気で勉強させてもらいました。またレイアウトに関しても、実はSwing等のリッチクライアントでも「コードから構築したほうが速い(IDEのサポートが必要)・はまらない・テスタビリティが高い」という方針で、通常はレイアウタやテンプレートは使わなかったりします。がしかし、それだとレイアウタやテンプレートの機能について勉強しなくなっちゃうので、やはり自分で調査すること無く知ることができたのは良い勉強になりました。気にしているものの触らない…が気にしている、みたいな状況のプロダクトについての説明を経験者から聞けるのはホント助かりますね。

@tmatsuoさん、@IanMLewisさん、@shin1ogawa: Google I/O 報告

@tmatsuoさんには無理言って、前日開催されたGTUG東京のI/O報告会と同じ Building Enterprise Applications on App Engine を話してもらいました。個人的にすごい気に入っていて、時間を使って話してもらいたかったからです(GTUG東京の報告会では3分縛りがあったw)。課金体系の変更には賛否両論(主に「否」かもw)たくさんありますが、Google様の事だからうまいバランスで調整してくるだろうなーと思ってあまり心配していません。他に印象に残ったのは、例のRoyal Weddingのサイト、32,000req/sと大規模だったのに「特にそれに向けて何か準備とか調整したわけではない」という事です。我々と同じ条件でそのスケーラビリティを発揮したのですね、素晴らしい。なんでI/OのregistrationでEC2ではなくAppEngineを使わなかったんry

私の資料は http://goo.gl/DGZMJ に置いてあります。

@IanMLewis さんの Go on App Engine は、Go利用者が少ない中での発表となりましたが、個人的にはGo on AppEngineの雰囲気を伝えるためにも必須だったと思います。RPCについて他の言語とそんなに大きく違うわけではなく、敷居が高いものではないよと伝わったんじゃないかと思います。IDEのサポートがまだ弱い(IntelliJ, Eclipseしか見てませんが)上に、Pythonのように簡潔には書けない…ように見えるのが残念ですが。I/Oのどのセッションだったか忘れましたが、将来の話として「BackendsにJava, Pythonのマルチスレッドサポート云々」というような話がちょろっあったんですね。自分としてはそれを「ついでにGo Runtimeも乗ってくるんだろなーそれならBackendsでは、GoRoutineで簡潔に書ける&高速に実行出来るGoで書くことになるだろな(Googleはそう考えてるだろな)」と考えていたので、Go on AppEngineは重要な事だと思ってます。ひがさんがヤケに「Goいらんだろ」とおっしゃてましたが、それはFrontEnd(経由のAppServer上)の話だと思います。たしかにそっちでGoは必要なさそうですね。

BeerTalk: Backends他

このあたりは1.5.0プレスリリースで知られていたことだし、前回のajnでも話題に上がった話なのでサラッと流させてもらいました。ただ、@drillbitsさんは女子と話していて聞いてくれていなかったそうです、ヒドイ。

BeerTalk: @bluerabbit77jp さん: Frontend cache control

資料も上がっていますが、これはI/Oのセッション Scaling App Engine Applications で Guido が話していたプラクティスとして紹介されていました。@bluerabbit777jpさんは17,000円程度のcpu使用量が0円になったそうです。ただしこの機能はBilling Onじゃないと使えないから注意!という説明もありました。
ついでに書いておくと、話が終わった後に、とあるGooglerの方がわざわざ前に来て「あ、ちょっとこれには注意が必要なんです。billing onじゃないとry」とか言い出したりしていたので、この人もやはり女子と話していてBeerTalkをちっとも聞いていなかったようです、ヒドイっすな。

BeeeTalk: @knj77 さん: Zusaarの紹介

参加費の決済もできるイベント開催支援サービス「Zusaar」

すいません、女子と話していて聞いていませんでした。

BeerTalk: @kissrobberさん: クラウド時代の新しいソートアルゴリズムTask Queue Sort

資料も上がっています。例のsleep sortをクラウド時代に…という話でコレは相当おもしろかった。こういうのは毎回一つ欲しいですね。

感謝

今回も会場を提供してくださったニフティ株式会社様、会場での準備・案内・片付けなどをしてくださったスタッフの皆様、大変ありがとうございました。告知に失敗したところをフォローしてくれた @tagomorisさん、大変ん助かりました。またいつもUst, ピザ&ビールの面倒を見てくださる@kazunori_279さんありがとうございます&次回もよろしくお願いいたします。
そして盛り上げてくださった参加者の皆様方、スピーカーの皆様方、大変ありがとうございました〜

その他

I/O終了からこの2週間、会社の仕事、ajnの他でもI/O報告系のイベント、I/Oで見ていないセッションを消化、等々で忙しかったです。特に見ていないセッションの消化に関しては、英語力がかわいそうなかんじの自分は動画の消化も実時間の3倍くらいかかってしまい、相当時間を消費してしまいました。そのあたりについて関連リンクを貼っておきます。

次回

7/2(土)に開催されるかもしれません…?なぜ土曜日なのか、は想像しておいてください。詳細が決まれば、参加費の決済もできるイベント開催支援サービス「Zusaar」で告知される予定です。

2011年5月16日月曜日

Google I/Oの #appengine 関連セッション動画一覧 #gaeja

5/10, 5/11に開催されたGoogle I/Oに初参加してきました。Google App Engineについては1.5.0のプレスリリースが事前にあったり、それを含んだappengine ja night 15が開催されたりしていたためインパクトは小さかったですが、golang他いくつかビックリの話も出ていました。個人的にはGoogle Appsの方がアツかったなー、という印象です。現地では、I/Oに生で参加できたという点よりも、超絶優秀なGoogle API Expert達と一緒に参加・行動できた、というオプションが一番すごい事だったかもw API Expertのみなさんお世話になりました。部屋をシェアしてた @IanMLewis@atusi さんは特にありがとうございました。

帰ってきてからは情報を整理したり、手を動かして試したいものは試したり、色々と作業がてんこもりで大変です。で、見ていないセッションはもちろん、参加したセッションも動画で復習したり…といった時に便利なように、App Engineの全セッションとそれ以外の一部のセッションの動画を一覧にしました。I/Oの公式サイトの各セッションの詳細ページだと、動画へのリンクが無いものもあったりして不便なため、動画へ直接リンクをはっています。

Google App Engineセッション一覧

その他 shin1ogawaが気になったセッション

参加できてないし、まだ観ていないものもありますが。Google Apps Scriptはアツイ事になりましたね、商売あがったりですね!Appsはここのあげたもの以外にもありますが、Appsでメシを食っている人は最低限ここに上げたものはチェックしておいた方が良いです。

Androidは社内の若い衆に任せてますし、GWTは触らないので含んでません。サーバ側ばっかりです。

2011-05-19 追記

Google API Expertの @IanMLewis さんが1.5.0リリースについてのエントリを作成されました。

2011-05-28 追記

一部のセッションでSlideやNotesが公開され始めたので、それらも含めた一覧にしました。I/O報告会などでさらに興味を持ったセッションが増えてたりしますが:)

2011年5月7日土曜日

#appengine ja night #15( #ajn15 )が開催されました

5/6(金)にappengine ja night #15が開催されました。人数は数えてませんが今回も女性参加者率が悲しい結果になり、むさい空気の中開催されました。

今回も@drillbitsさんがtogetterにまとめてくれています、ありがとうございます。

AppEngine テスト駆動開発

AppEngine/Pythonでの自動テスト事情の説明でした。まだ全然触っていないけど個人的には1.4.3からPython SDKに導入されたTestbedについておおよそ仕組みがわかってよかったです。Testbedはsetup等で細かく制御できそうなのはメリットでもありデメリットであるかもしれませんね。
でも、結局はアプリ用のF/Wと一緒になっている方が良いので、@tagomorisさんが作ったF/Wをベースにしたテスト支援機能を持つKay-frameworkがヨサゲなんだろな、と。

Gig in a Nutshell

個人的にずっと興味を持って見ていたAcid Houseの流れでGigも興味を持って見ていて(特にScaffoldの部分)、登壇をお願いしました。PetStoreへのチャレンジに関するエントリもリアルタイムに追っかけていましたよ!会場の反応で面白かったのは、Gigのプロダクトへの反応よりも「いちいち命名がかっこよすぎる(アノテーション名までかっこよい)」「ひとりで作ってるのかすげぇ!」の方が盛り上がっていた気がします。

appengineでクーポンサイトを作った話

スポーツSNSのLaBOLA(ラボーラ)に実装されたクーポン系の機能の紹介。ですが「資料がnajeiraさんらしく無い!」という話で盛り上がりました。
個人的に「あーなるほど」と思ったのは、チケットの予約に関しては「厳密にはチケット数を超えて予約できてしまう可能性もある」という話で、それはPaypalの方では一旦決済を保留しておき、最終的に決済を確定するしないを決めればいい、的な話でした。なるほど。

ちなみにこのエントリを書いている途中でクーポンサイトを見に行ったら「加圧トレーニング」のクーポンがあったのでに紹介しておきました。

Google App Engine 1.4.3 で追加や変更された機能を紹介

1.4.3で追加された機能を15分程で説明する予定でしたが、開催前々日くらいに1.5.0のプレスリリースがあったため、急遽そちらの内容も含めることにしました。appengine ja night開催日付近にsdkのリリースをぶつけてきて慌てさせるGoogle様の手法は相変わらずですね。というか、1.5.0の方が面白そうな機能が多そうなのでそっちがメインになってしまっています。

オフレコでのトークも含まれるため、Ustでは音声が切れている箇所もあると思われます。そこは想像で補完してください。また、うっかりしてWaveを公開状態にしていなかったようです、すいませんでした。

@soundTricker318さんがslim3-gwt用のmaven-archetype-pluginを作っている事を教えてもらいました(気づいてませんでしたすいません)。maven+appengine+GWTあたりの調査・試行錯誤はGWT弱者な私ではあれこれめげてしまう事が多かったので大変ありがたいことです。

今回も、TL上では面識があるものの一度も挨拶出来ていない方とご挨拶できました。ありがとうございました。

najeiraさんの資料はコミポというサービスを使ったらしい。

kazunori_279さんのMBPの背中のシールGelaSkinsというサービスで作れるらしい。

感謝

今回も会場を提供してくださったニフティ株式会社様、会場での案内などをしてくださったスタッフの皆様、大変ありがとうございました。またいつもUst, ピザ&ビールの面倒を見てくださる@kazunori_279さんありがとうございます&次回もよろしくお願いいたします。盛り上げてくださった参加者の皆様、スピーカーの皆様も大変ありがとうございました!

次回予告

次回はappengine ja night #16ですが、5/27(金)19:00から、今回と同様ニフティ株式会社様の会場をお借りして開催いたします。既に決まっているコンテンツは以下のとおりです。

appengine ja night二人目の女性スピーカーの登壇となります。Android女子部の方々も是非参加してみませんか?AppEngineを簡単に使うためのjsonengineというプロダクトを作っているメンバも参加しますので、その場で質問や要望をぶっつけたりする事もできますよ。
そんなカンジで是非ともたくさんの女性の方にも参加していただきたいです。いつもすぐ定員に達してしまうappengine ja nightですが、女性参加者の場合は専用の枠をいくらか用意するつもりですのでatndの定員の心配をしなくても大丈夫です、是非どうぞ!

2011年4月3日日曜日

#appengine 1.4.3の #slim3 単体テスト環境でQueueへのAddで例外が発生する場合

追記

このエントリを書いた数時間後に、この問題に対する対策が実施されたslim3-1.0.10がリリースされています。このエントリは無視してそれを使いましょう!

Slim3の単体テスト環境で、先週リリースされた Google App Engine SDK 1.4.3を適用するとQueueへTaskをaddする処理で次のような例外が発生します。

java.lang.IllegalArgumentException: Task name does not match expression [a-zA-Z\d-]{1,500}; given taskname: 'null'
 at com.google.appengine.api.taskqueue.TaskHandle.validateTaskName(TaskHandle.java:103)
 at com.google.appengine.api.taskqueue.TaskHandle.(TaskHandle.java:30)
 at com.google.appengine.api.taskqueue.QueueImpl.add(QueueImpl.java:489)

あれこれ見てみた結果、この原因は、1.4.3 からSDK内でtaskqueue#BulkAddのresponseをチェックするようになった、という事かなと思います。

対処方法

Slim3内部でなんとかするしか無いですが、急いでいる方は次のようにすると応急処置になります。

  1. Slim3を使ったプロジェクトに、org.slim3.tester.AppEngineTesterを作成する
  2. Slim3のorg.slim3.tester.AppEngineTesterをそのクラスにまるごとコピーする
  3. 次の箇所を探す。
    } else if (service.equals(TASKQUEUE_SERVICE) && method.equals(BULK_ADD_METHOD)) {
      TaskQueueBulkAddRequest taskPb = new TaskQueueBulkAddRequest();
      taskPb.mergeFrom(requestBuf);
      TaskQueueBulkAddResponse responsePb = new TaskQueueBulkAddResponse();
      for (int i = 0; i < taskPb.addRequestSize(); i++) {
        tasks.add(taskPb.getAddRequest(i));
        responsePb.addTaskResult();
      }
      return responsePb.toByteArray();
    
  4. その箇所を次のように変更する。
    } else if (service.equals(TASKQUEUE_SERVICE) && method.equals(BULK_ADD_METHOD)) {
      TaskQueueBulkAddRequest taskPb = new TaskQueueBulkAddRequest();
      taskPb.mergeFrom(requestBuf);
      TaskQueueBulkAddResponse responsePb = new TaskQueueBulkAddResponse();
      for (int i = 0; i < taskPb.addRequestSize(); i++) {
        tasks.add(taskPb.getAddRequest(i));
        TaskResult taskResult = new TaskResult();
        taskResult.setChosenTaskName("task" + String.valueOf(System.nanoTime()));
        responsePb.addTaskResult(taskResult);
        // responsePb.addTaskResult();
      }
      return responsePb.toByteArray();

ついでに

どうせSlim3のクラスにパッチをあてるなら…という事で、テスト時の初期ファイルをSlim3の単体テストで使用してテストの処理時間を短縮したい、等考えている人は次の対処をしておくと便利かもしれません。

AppEngineTester#tearDown()内のApiProxy.setDelegate(originalDelegate);となっている箇所の後ろに次の処理を追加する。

if (!AppEngineUtil.isProduction()) {
  ClassLoader loader = loadLibraries();
  Class apiProxyLocalImplClass = loader.loadClass(API_PROXY_LOCAL_IMPL_CLASS_NAME);
  Method stopMethod = apiProxyLocalImplClass.getMethod("stop");
  stopMethod.setAccessible(true);
  stopMethod.invoke(apiProxyLocalImpl);
  ApiProxy.setEnvironmentForCurrentThread(originalEnvironment);
  new File("build/test-classes/WEB-INF/appengine-generated/local_db.bin").delete();
}   

単体テスト用の初期データファイルをSlim3の単体テスト実行フォルダ(build/test-classes/WEB-INF/)にコピーしてテストする際は、データストアを正しく終了する処理をしておかないとデータファイルが正しく読めなくなってくる(タイミングによっては問題なく読める時もあるw)ための対処です。念には念を入れてlocal_db.binの削除も行っています。この対策を行って、AppEngineTester#setUp()の前に初期データファイルを"build/test-classes/WEB-INF/appengine-generated/local_db.binへコピーしておけばテストのための初期データ作成が高速になります。

2011年3月22日火曜日

クラウド設計のデザインパターン@ITPro #appengine

本日3/22日より、ITproにてクラウド設計のデザインパターン - クラウド設計のデザインパターンという特集が始まりました。そのシリーズの中のGoogle App Engine編という事で、金曜日までの4回分を執筆させていただきました。

あまりガッツリ開発をする人ではない読者を対象にということで、開発者の方にとってはもの足りない内容かもしれませんが、これからGoogle App Engine向けにシステムを構築しようと考えておられる方にはどんな点で苦労があるのか?などなどと参考にしていただけると思います。いきなり「よっしゃGoogle App Engine向けの案件を開始するぜ」みたいなノリでとっかかると大概痛い目に遭うプラットフォームだと思うので、これから始めようと考えている方には是非4回全部読んでいいただきたいです。

Google App Engineプラットフォームはかなり速い速度で進化し続けているため、もっと開発者向けのものも、今回の連載とは別にそろそろまとめておく必要があるなぁと、執筆を進めながら思ったりしました。

2011年3月12日土曜日

MacOS Xのアップデート後 #appengine javaで開発サーバが動作しない件

2011-03-11にあったMacOS Xのアップデート実施すると、ローカルで開発サーバが起動できなくなる問題が出るようです。現象としては、開発サーバ(eclipseから起動しても、結局はSDK内のdev_appserverが起動されます)を起動した後、数秒で開発サーバが終了してしまう、という現象です。私が試したときはたまーに少しだけ動作してから落ちる、という場合もありました。下記でも報告されていますし、対策も説明されています。

対策を簡潔に説明しておきます

  1. http://openjdk-osx-build.googlecode.com/files/OpenJDK-1.7-x86_64-20110221.dmg からOpenJDK1.7のイメージを入手する
  2. dmgを開いて、DukeアイコンのInstallation.pkgを実行してOpenJDK1.7をインストールする

これでopenjdk-1.7がインストールされます。此処から先は開発サーバの起動毎に手順があります。

SDK内のdev_appserver.shを直接起動している人

dev_appserver.shをエディタで開いてJAR_FILE=...などの次の行あたりにJAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk-1.7-x86_64/Contents/Homeを追加する

eclipseから起動している人

  1. eclipseの設定画面を開く
  2. 左のツリーからJava > Installed JREsを選択する
  3. 右側のペインでAddをクリックする
  4. Add JREダイアログでMacOS X VMを選択してNextをクリックする
  5. JRE definitionの画面に移るので、JRE HomeDirectoryボタンをクリックして/Library/Java/JavaVirtualMachines/openjdk-1.7-x86_64/Contents/Homeを選択する
  6. JRE nameopenjdk-1.7-x86_64を入力する

ここまでの手順で、eclipseがOpenJDK1.7を認識出来るようになります。次に、appengineプロジェクトに対して次の設定を行う必要があります。

  1. プロジェクトのプロパティを開き、左のツリーからJava Build Pathを選択する
  2. 右側のペインでLibrariesタブを開き、リストの下の方にあるJRE System Library[JVM 1.6.0 (MacOS X Default)]を選択し、Removeをクリックして削除する。
  3. Add Libraryボタンをクリックする
  4. Add LibraryダイアログでJRE System Libraryを選択してNextをクリックする
  5. どのJREを使うか選択する画面になるのでAlternate JREを選択し、先の手順でEclipseに認識させたopenjdk-1.7-x86_64を選択する
  6. プロジェクトのLibraryにopenjdkが追加される。

これらの手順で開発サーバが起動できるようになります。

追記

上記手順で開発サーバを起動したときにjavax.net.ssl.SSLExceptionが発生するのが気になる場合は、次の手順で解消できます。

  1. cd /Library/Java/JavaVirtualMachines/openjdk-1.7-x86_64/Contents/Home/jre/lib/security
  2. cp /System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security/cacerts .

2011-03-15追記

AppleのJDKを入れ直すという、もっと簡単そうな手順も紹介されています。

2011年2月24日木曜日

Google API Expert(Google App Engine)に選任していただきました

Googlerとなってからはぐれメタル並の出現率となった@kazunori_279さんの推薦により、Google API Expoertとして活動させていただくことになりました。

  • Google App Engineに関する情報発信
  • 初心者向けの普及活動
  • appengine ja night等の濃いコミュニティへの協力

…などなどの活動はこれまでどおり行いつつ、これまでよりもGooglerとの接続ができるかなと思います。

また、個人的には Google Apps関連APIやその他のGoogle APIも色々と触っているので、他のAPIのExpertの方々とも連動してAppEngine以外のAPIを使うデベロッパーの方々ともコラボできるようなハンズオン・ハッカソン・勉強会もやっていきたいと考えています。今後とも宜しくお願いいたします!

2010年12月26日日曜日

#slim3 1.0.6 のSimpleControllerを使った場合のテスト方法 #appengine

先日、slim3-1.0.6がリリースされました。たくさん機能追加がありますが、最近の自分的に嬉しい機能のひとつにController内でInputStreamが使えるissue62への対応があります。

Support for Controller#createRequestHandler():
http://code.google.com/p/slim3/issues/detail?id=62
この機能を使用する際のテストケースの書き方の例を書いておこうと思います。あと、ついでにMetaクラスにJson->Model、Model->Jsonを行うユーティリティメソッドが追加されているのでそれも使っています。@takawitterさんの仕事です、ありがとうございます、便利です。

まずはController

Httpメソッドとリクエストパラメータによって追加・修正・削除と1件返却、リスト返却を実装しているだけのシンプルなものです。ポイントはControllerではなくSimpleControllerクラスを継承している点と、asString()は使わずrequest.getParameter()でパラメータを取得するという点と、ModelMetaクラスのJson用ユーティリティメソッドが便利という点です。

ControllerをテストするControllerTest

ServletInputStreamを実装したJsonInputStreamというクラスを用意し、MockHttpServletRequest#setInputStream()に設定することでControllerへのpayloadを設定しています。

issue62とJson用ユーティリティメソッドのおかげでjsonをやりとりするControllerが一気に作り易くなって、かなーり助かります。ただ、jsonArrayToModels()modelsToJsonArray()が無いのがちょっと勿体無いかな?

2010年10月15日金曜日

#slim3 のテスト環境で投入したデータを削除せずファイルに保存する #appengine

AppEngine/Javaで、開発サーバで実行するときのテストデータの初期状態を作っておきたい時、私はよくAppEngine SDKのLocalServiceTestHelperを使ってテスト環境を作成してデータ投入し、そこで作成したファイル(local_db.bin)をwar/WEB-INF/appengine-generatedフォルダにコピーしていました。これと同じことをSlim3のAppEngineTesterを使ってできないかなー?と思って試してみました。

Slim3のAppEngineTester#tearDown()はテスト中に投入されたデータは全部消してしまう(それが便利なわけですが)仕様です。これはtearDown()をオーバーライドして削除処理をしないようにすれば回避できます。
それだけだと良いんですが、環境終了時にApiProxyLocalImpl#stop()を呼んでいません。これが無いとデータがlocal_db.binに永続化されないので、ファイルが作成できません。そこで次のようなAppEngineTesterのサブクラスを作って使うことにしました。テスト中に投入したデータのクリア処理を外し、各LocalServiceクラスを停止するためのApiProxyLocalImpl#stop()を実行するようにしただけです。

以下のように使うことになります。

  1. テストデータ投入前に、上記のAppEngineTesterのサブクラスをインスタンス化し、setUp()を実行する
  2. 開発サーバで実行するときのアプリケーションIDを返すApiProxy.EnvironmentのインスタンスをApiProxy#setEnvironmentForCurrentThread()で設定する
  3. テストデータを投入する
  4. 上記のAppEngineTesterのサブクラスのオブジェクトのtearDown()を実行する
  5. build/test-classes/WEB-INF/appengine-generated/local_db.binwar/WEB-INF/appengine-generated/local_db.binにコピーする

データファイルに保存されるエンティティにはアプリケーションIDも合わせて永続化されるので、データ投入時と開発サーバ実行時で同じになる必要がある点に注意が必要です。

2010年9月22日水曜日

#appengine の開発環境でfederatedLoginなアプリを動作させる

appengineのfederatedLoginの機能を使ったアプリケーションの場合、開発環境のログイン機能ではcom.google.appengine.api.users.UserからfederatedIdentityの値などが取得できずに不便です。実行時のUserService#isLoggedIn(), UserService#isAdmin(), UserService#getAuthDomain()等はApiProxy.Environmentを自身の実装に置き換えるだけだったので簡単でしたが、federatedLoginの場合はこれらの値を触るだけでは不十分です。
ではいつものようにApiProxy#setDelegate(ApiProxy.Delegte)でいじってやるか!というワケにもいきません。UserService#getCurrentUser()等はRPCされないためです(以前、本家MLで「UserServiceはコストが低い」という話がありましたね。その理由はRPCしない=コストが低い、ということです。このブログでもいつだったかに書いた記憶があります。)。

んじゃどーするのか?といいますと、ApiProxy#getCurrentEnvironment()で取得できるApiProxy#Environment<ApiProxy.Delegate>Map<String, Object>#getAttributes()メソッドが返す値を操作してやるのです。

ApiProxy#Environment<ApiProxy.Delegate>#Map<String, Object>#getAttributes()に以下の要素を設定してやることで、federatedLoginの機能が開発環境でも有効になります。

  1. com.google.appengine.api.users.UserService.is_federated_user
  2. com.google.appengine.api.users.UserService.user_id_key
  3. com.google.appengine.api.users.UserService.federated_identity
  4. com.google.appengine.api.users.UserService.federated_authority

com.google.appengine.api.users.UserService.is_federated_userについてはBoolean.TRUEを設定しておく必要があります。他はすべて文字列を設定すればよく、それぞれの値はfederatedLogin機能を使うときのアレです。

単体テスト環境では、ApiProxy#Environment<ApiProxy.Delegate>Map<String, Object>#getAttributes()が返す値に上記を追加し、ApiProxy#setEnvironmentForCurrentThred()してやれば良いです。
開発サーバ環境でも同じことをすれば良いのですが、私が使っている「専用のFilterとして実装する」という方法のサンプルコードを掲載しておきます。
「独自のApiProxy#Environment<ApiProxy.Delegate>を常に使用する」「createLoginURL()すると、専用のフォームを表示し、そこからのPostの内容に従ってfederatedLoginUser情報を設定する」「web.xml内でinit-paramにfederatedLoginUser情報があれば、それを読み込んで起動時からログイン状態にしておく」等をやっています。
単体テスト環境では、下記のサンプルコードの内部staticクラスとして定義されているFederatedLoginEnvironmentをインスタンス化して、loginメソッドなどでfederatedLogin状態を作り出し、ApiProxy#setEnvironmentForCurrentThred()すれば良いですね。

2010年9月11日土曜日

#appengine javaでURLFetchのdeadlineを自動的に設定する

AppEngine/JavaでのURLFetchサービスのdeadlineは5秒だと思うけど、全てのURLFetch#fetchのdeadlineを自動的に10秒に設定するためのApiProxy.Delegateの実装を作成してみた。

仕組みはとても簡単、

  1. URLFetch#fetchをフックして、サービスへリクエストされるバイト配列からURLFetchRequestに組み立てなおす。
  2. 組み立てなおしたURLFetchRequestURLFetchRequest#toBuilder()を使って、新たにURLFetchRequestを作成し、それに対してURLFetchRequest.Builder#setDeadline()する。
  3. setDeadline()したオブジェクトをバイト配列に変換し、
  4. サービスには何食わぬ顔でそのバイト配列を送りつける。
gdata-apiを使うときなんかは5秒じゃ済まない事も多いので、Slim3なら基底クラスとしてGDataAPIControllerBaseとか作って、setUp()/tearDown()でこのDelegateのつけはずしをしたりして使います。

2010年7月28日水曜日

#appengine #slim3 本を執筆しました

Slim3本?データストア本?

Google App Engineのデータストアに特化した内容の書籍(Slim3本)を執筆し、本日刊行されました。

Seasarで有名なひがやすをさんが作っている Slim3 の書籍で、ひがさん本人から執筆の機会を頂くことができたのがきっかけです。色々とあって執筆する時間が取れないから書いてみない?というおはなしで、しかも方針は「データストアだけに特化した書籍にしたい」というお話だったので驚きました。私はSlim3のテストサポート機能がとても気に入っているので、Controller周りとそのテストとか、どさくさに紛れてLowerな話も含めたりとか考えたのですが、書き上げてみて納得しました。データストア以外はそんなに深いハマリも無いし、他にも書籍がありますし、データストアだけに特化するというのも集中した内容になってよかったと思っています。

右にAmazonへのリンクを貼ってみましたが、表紙画像がまだみえてませんね(7/28現在)。表紙画像や目次が秀和システムさんのサイトで公開されていますので、購入する前に確認することもできます。ひがさんが監修と1章2章の執筆を、私は3章〜7章を担当しています。

ひがさんが既にこの書籍の紹介をされていて、シンプルにまとめられています。その中では次のような事が書いてあります。

  • データストアを理解し使いこなすことに特化している
  • データストアに関するひがさんや私が持っているありったけの知識と経験が詰められている
  • 初心者向けではないが、初心者でも理解できるよう書いている

初心者向けではないが…の点について。たしかにターゲットは中級者〜上級者向けです。しかしひがさんも書いておられるように初心者でも読めるようかなり噛み砕いて書いてありますし、私の考えとしてはGoogleの公式ドキュメントを読む前にぜひとも読んで欲しいと思っています。

データストア以外も学習するには?

中田先生の「すっきりわかるGoogle App Engine for Javaクラウドプログラミング」が一番新しく、各機能について網羅されているのでオススメです。

書籍以外では、9月末ごろに開催されるGoogle Developers Day Bootcampで初心者向けのSlim3のハンズオンも開催しますし、appengine ja hands-onも開催したいと考えています。
それとこれは営業になってしまいますが、株式会社トップゲートでは有料のGoogle App Engineみっちりセミナーも定期的に開催していく予定です。まぁこちらは企業からの参加を想定していますので個人では参加できそうにない価格設定ですけれども(それでも前回開催時は個人での参加者が3人ほどおられて仰天しました)。

そんなワケで、皆様おまたせいたしました&ひがさんエキス100%じゃなくて申し訳ない。でもひがさんが監修してくださっていて、全体的な構成やらの監修はひがさんがやってくれていますよ!

2010年7月23日金曜日

PubSubHubBubを経由してBuzzのFirehoseを #appengine で使ってみる

ちょっと前に BuzzでFirehoseが使えるようになりました。

今の空うさぎでは、FriendFeedはリアルタイム(FriendsがPostした瞬間にクライアントに通知される)になっていますし、TwitterもUserStreamを使うことでFirendFeed同様にリアルタイムになっています(Twitter側の制限のために、リリース版ではTwitterのリアルタイムはオフになってますが)。さらに開発版ではGoogle Buzzも利用可能になっています。であればBuzzもリアルタイムに…!と思うんですが、これがTwitterやFriendFeedとはちょっと仕組みが違う。Webアプリでしか使えないようです。なので、AppEngineで受けてXMPP経由で空うさぎに送ってしまえないか?という事でPubSubHubBub を使ってAppEngine/JavaでBuzzのFirehoseを使ってみようかと、そんな流れです。
ここではまずはリアルタイムに取得されるBuzzのActivityをデータストアにどんどん保存するアプリを作ってみます。

まずAppEngine/Javaのプロジェクトを作る

slim3のarchetype-pluginを使って簡単にプロジェクトを構築します。

  1. $ mvn archetype:generate -DarchetypeCatalog=http://slim3.googlecode.com/svn/trunk/repository
  2. Projectの生成が対話形式で進むので、質問に従ってプロジェクト名などを入力
  3. $ cd ${プロジェクト名}
  4. $ mvn eclipse:eclipse
  5. Eclipseでインポートします。

BuzzのActivityを保存するモデルクラスを作成

今回はお試し程度なので、Atomの解析はせずにそのまま格納するようにします。

PubSubHubBub用のコントローラを作成

http://myapp.appspot.com/subscriberというURLでPubSubHubBubをSubscribeすると想定して、それをハンドルするようにします。ここではSlim3のControllerを使います。

PubSubHubBubでSubscriberの登録をする

  1. 先の手順で作成したアプリケーションをデプロイします。
  2. http://pubsubhubbub.appspot.com/subscribeを開きます。
  3. Callback: (the subscriber URL)に、先に作成したSubscriberのURLを入力します。例えばhttp://myapp.appspot.com/subscriberのようなURLになるはずです。
  4. Topic: (the feed URL)に、https://www.googleapis.com/buzz/v1/activities/@all/@publicを入力します。
  5. Do itをクリックします。

登録処理が問題なくAppEngineの管理コンソールのINFOレベルのログを見ると、subscribe: hub.challenge=...のようなログが出力されるはずです。

どんどん流れてきます

AppEngineの管理コンソールでall requestログを見るとどんどんリクエストが飛んできている事が確認できます。DatastoreViewerの"buzz"カインドにはどんどんエンティティが増えていきます。こんなカンジでfirehoseが使えます。が、恐ろしい勢いでデータがたまっていくのでちょっと怖いですね。

PubSubHubBubからSubscriberの登録を解除する

登録した時の手順と同様に、Callback: (the subscriber URL)Topic: (the feed URL)を入力して、Mode:Unsubscribeを設定して、Do itをクリックします。問題なくUnsubscribeができればAppEngineの管理コンソールのINFOレベルのログを見ると、unsubscribe: hub.challenge=...のようなログが出力されるはずです。

2010年6月6日日曜日

#appengine ja night #8( #ajn8 )に参加した

6/4(金)に appengine ja night #8が開催されました。今回の目玉は以下でした。

  • @najeiraさんトコで構築されたスポーツSNS Labolaの事例紹介
  • ajn7の時のランキング問題をやっつけるために京都より@koherさんがskip list片手に参加
  • 北海道より@shuji_w6eさんが参加
  • 名古屋より@zetta1985さんが参加
  • skip listと聞いて(ガタッ、ってかんじで大阪より@kibayos先生が参戦

本当は@kazunori_279さんのIO2010報告もあるはずだったのですが、上記の通り盛りだくさんでしたし、発表は必ず時間通りに終わらないajnの伝統が継承されてIO2010報告は次回持越しとなりました。
また、今回は以前と比べて女子率が3倍ほどにアップしました!…新規参加者と言うより、リピーターの方のお情け(同僚の方を連行してきてくださった模様w)という実態だったようですが…。今回もカオスってたし、もう来てくれないかもしれませんね(ノД`) これまでのajnでの女子のリピーターの方はぶいてくの方が一名だけですからね。

今回もappengineja channelでustが録画されています。メディアテクノロジーラボ様のすごい設備のおかげです。ちなみにすごいのカメラだけではありませんでした。

@najeiraさん - コミュニティサイトLaBOLAをappengineで開発してみた

タイトルの通り、コミュニティサイトLaBOLAの実際の事例紹介。4年前から運用していたサービスのフルリニューアルとの事らしい。

移植は向いていない、作り直す。言語レベルとかそういう問題以前にデータ構造がムリ。
アーキテクチャが全く違う、という事をちゃんと意識しなきゃダメですね。自分は、そのあたりを油断して、RDB向けに設計されたものをそのまま乗せようとして大変な目にあった苦い経験がありますし。
インフラエンジニアが必要なくなった
その後会場向けに「あ、この中にインフラエンジニアの方はいません…よね?」→「数人が手を上げる」…の流れにわらった
Proxyを使って、AppEngineをバックエンドとして使用している
Proxy挟んだらそこがネックになってまうやん、という当然の質問も上がったが、ngixというヤツがかなりすごくて平気らしい。
AppEngineに移行後は、速くなり、安くなった
素晴らしい。でも、最近はデータストアの遅延で悩んでいる人のこと。遅延についてはあと2週間ほど我慢するしか無いっすね…。
技術的にはたいしたことない。データストアもやればできる
かっこいい!

@koherさん - Skip Listによる高速な順位・平均等の計算方法

Skip List→Indexable Skip List→それをAppEngineで実装するには?、という流れでの説明で、資料と手順がよくわかりやすかったです。自分はアルゴリズムはあんまり知識が無いのですが、わかりやすい説明のおかげで大分把握できました。だがしかし盛り上がりすぎて時間内に終わらず懇親会に突入して続行、すると各テーブル(MTLさんの会場は6つくらいのテーブルに分かれている)ごとにゲリラ議論が発生して超カオスな状態になるという、ajnらすぃ展開となりました。

@kibayos先生、@zetta1985さん

…すいません、ビールを買出しに行ってしまったため聞けてません><。後でUstで確認ですね。

@shuji_w6eさん - 泣かないAppEngine開発

主にspinup時の問題と工夫についての説明。その解決のために生まれたプロジェクトの説明。

scenic3
t2framework用のハンドラ定義(アノテーションを使う)からAPTでSlim3用のControllerを生成する、というかなーーーり興味深いフレームワーク。t2大好きな自分もappengineではt2封印しているのだけど、これは素晴らしい。いくつかあるプロジェクトのどれかひとつをscenic3で置き換えてみたいなぁ。
kotan
Swingをやりこんだ自分としてはかなり興味が湧いて面白いと思った。が、実は似たようなやつをEclipsePluginとして構築しているので、ライバルプロジェクトとなりそうで面白いと思った!自分の場合はオリジナルのRemoteApiですけどね。ちなみに最近のAppEngine案件でも、デカイデータをダウンロードしたいという要件を満たすためにJWSを使ったりしてます。

面白かった試み

@urekatさんが、tsudaるのではなくwaveにまとめるという事を試していました。@urekatさん以外には主に@y_kohさんと私も手伝っていましたが、今回は@najeiraさんの発表までで力尽きてしまいました。3人でもおっつかないのと、日本語入力が不能になる不具合の問題が結構ダメージがでかかったですね(一文字だけ入力した瞬間に日本語入力できなくなり、仕方なくローマ字で入力しておいて、それを見ていた別の人がリアルタイムに日本語に置き換える、という人力IMEが発動してたりして面白かったけど)。次回からは、5-6人くらいwave担当を決めて、協力しあってリアルタイム編集していく体制を事前に決めておけばかなり面白いと思いました。内容と会場のノリという意味ではtogetterよりもわかりやすくまとまるでしょうね。もちろん、togetterの方が向いている点もあるのでそれはそれで毎回使わせていただこうと思います。

感謝

いつも会場を提供してくださるリクルートメディアテクノロジーラボ様、川崎様、大変ありがとうございました。いつも開催に関するしきりをしてくださるスティルハウス佐藤さん、ありがとうございます&次回もよろしくお願いいたします。盛り上げてくださった参加者の皆様、スピーカーの皆様大変ありがとうございました。

過去の参加報告

ajn6の報告を書き忘れてますね…><

2010年4月24日土曜日

#appengine ja night #7( #ajn7 )に参加した

4/23(金)にappengine ja night #7が開催されました。ATNDを見るとshin1ogawa ja nightとか書かれていてこっぱずかしいような嬉しいような…。今回の目玉は以下でした。

  • ライブコーディングを使って、appengine/javaがいかにテストしやすいか?をお伝えする
  • 事前にGoogle Moderatorで議題・質問を募集し、それをネタに会場で議論する
  • イベント開催中は京都のサテライト会場とつなぎ、双方向のやりとりもする

@kazunori_279さんがUstしつつ録画してくださっています。

appengineアプリケーションの自動テスト -最新java sdk版-

一番伝えたかったことは、通常のWebアプリケーションと比較して、AppEngineアプリケーションはとてもテストがやりやすいという事です。

  • データベースなどについての考慮も少なく済むし、高速に実行できる
  • 外部サービスから例外が投げられるようなケースも簡単にテストできる
  • Memcache, Queue等の外部サービスを利用する機能のテストもラク

以下はこれをライブコーディングした側から見た感想です。

自分が実装を間違えてそのまま進みそうな点について、リアルタイムにツッコミを頂くことで無駄なハマリ時間を回避することができた点がいくつかありました。指摘してくださった方ありがとうございます。これがソースコードレビューやペアプロのパワーですね。また、TDD的な観点では @t_wadaさんからのフィードバックを直接頂くこともできたため、今後 appengine ja night ハンズオンなどをする際により良い内容ができそうです。またslim3 作者のひがさんからも、slim3的にもっと便利にテストする方法などを教えていただけました。やっぱ人前に自分のコーディングを晒すのは大変良いことですね、質の良いフィードバックをたくさん頂戴しました。

eclipseの操作についていくつか質問がありましたが、自分のeclipseは以下の仕様です。

  • quick-junitプラグインを導入。
  • favoritesにJunitのAssertとhamcrestのMatchersを登録してある
  • Launchingの設定で「always lanch the previously ...」を設定してる

キーバインドとかは全く設定していないドノーマルな状態だし、自分もまだ無駄が多いのでeclipseのフルパワーは引き出せていません。eclipseたんが本気出せばもっとスゴイです。プロジェクトごとに細やかにカスタマイズしたテンプレートとかを導入しはじめるともっとえぐい事がになります。

appengine QA大会

java組代表として@higayasuoさん、python組代表として@najeiraさんに色々意見を披露していただき、その後会場から意見を募るといった形式となりました。かなり濃いめの内容になったんじゃないか?と思いました。会場にてメモを取っていた内容を書いておきます。

appengine 向きのアプリケーションってどんなアプリケーションでしょうか?またappengine に向かないアプリケーションってどんなアプリケーションでしょうか?
自分たちでサービスを作りたい、など作りたい人が作るには向いてる。受託とか、誰かに作らせると言うタイプは向いていない / 業務系の性能要件とかも自分たちで決められない状況ではキツイ / 課金の見積がしづらい(主にCPU使用量について)
ランキング問題みたいに、逆にどんなケースで困っちゃってるか聞きたいです。必勝パターンを確立したい! / 業務系システムで使用するためにクリアするべき課題はなんですか?
ランキングはトップ10だけ正確にするなどする / mixiに限定した場合、マイミクを対象にすれば1000人で済むからできるね / twitterも最初の数千件は正確に処理できるけど、それ以降は無理だね
ページングどーやりますか。特定のページにリンクするとか → 各ページの先頭のKeyを覚えておけば良い / とはいえ、ページ内の件数が多いとかもあるだろし、最初からなんページ目かまでしか保存できない(shin1ogawa補足:これは1000件以上も考えた話です) / twitterとかもカーソルを使うようになってますね
csvダウンロード、大量データ処理など、主にタイムアウトを乗り越えるのに苦労する
必勝パターンというなら、全体の正確さを求めない事が勝ちパターンというか、全体の正確さを求めるのは負けパターンにつながるね
[アンケート]どういう目的でappengineを触ってますか?(1)趣味、知的好奇心など、探求目的 (2)お仕事、あわよくば仕事に使いたいなど、実用目的 (3)ビール祭りに参加できると聞いて
(1)はかなり多かったというかほぼ全員。京都会場の人も多数が手を上げていた / (2)もかなり多かった。shin1ogawa個人的には1/4もいないと思っていたが、2/3くらいいたような / (2')んじゃ実際仕事で使った経験がある人は?→東京会場で15人くらい、京都会場ではひとりだっけ? / (3)東京会場で3人くらい。というか選択肢として意味がわからないww
[アンケート]MapReduceサポートされたら、どんなことができますか?どんなことをしたいですか?
ログ解析等の大量データ処理 / リモートセンシング。複数のセンサーからのインプットを計算するプラットフォームとして使えないか / Twitterのストリーム等を自然言語処理
[余裕があればアンケート]appengineを使って運用されているサイトってどんな事例がありますか?
やっぱmixiアプリかな? / Xmaxのイベントとか / 衆院選でも / バックグラウンドという意味ならエコポイントのメール配信、TweetdeckのTaskQueue / 海外は結構多いよねー

ビール祭り云々についてないがしろにして申し訳ありませんでした。問題の議題を提供してくださった@marblejenkaさんは、製造終了日ギリギリに製造された、おそらく最後のキリンプレミアム無濾過をajn7会場に4本も持ち込んでくれていました。ビール祭りも重要です、このエントリにて訂正させていただきます。

BeerTalk

前回のなうまぴおんに続き、事例紹介が多かったのはとても良かったんじゃないかと。やっぱり実例を元にしたTalkはウケもよく、盛り上がりますね〜。次回以降も最低ひとつは事例の紹介Talkがあるといいっすねぇ。個人的にはふにゃもらけさんのmixiアプリの件に興味を引かれました。S3+CloudFrontは転送量が多いと結構お金もかかるんですね(appengineと比較して、ですけど)。mixiのモバイル向けCDNはPCアプリ用には支えないのかな?とか思いました。

反省

  • Ust, サテライト会場との接続…と、東京会場以外への発信も行う事が目標の一つだったんだけど、録画を確認する限り東京会場内での意見をUstやサテライト会場へ伝えるための復唱が甘い、拾いきれていない。これは前回もフィードバックいただいたことなので、意識したつもりだけど、意識しつつも復唱のタイミングを失ったと判断して何回かスルーしたのがよくない。割り込んででも「会場で〜という質問・ツッコミが」とイチイチ復唱すべき。後から録画を見る時の事を想定すりゃわかる事なのにぃ。次回はもっとこまめに動きます。
  • keycastr起動し忘れてた。ahack3でUstの確認した時は起動して確認したのにw
  • タイムマネジメント。BeerTalkにかかる時間見積もりを完全に見誤ってしまった。いつも見誤っていると言われればそーなんですが、当日会場でのそれへの対応が足りなかったと思います。事前の「15分をめどに」のアナウンスを怠ったのと、一本は最悪次回に回させてもらうという、BT提供者との打ち合わせができていなかったなーと。いちいさん、ほんと申し訳ありませんでした。
  • 京都会場とリアルタイムにつないでいたのですが、あまり頻繁なやりとりができなかった。こちらからは京都会場のスピーカ付近以外の声が確認できなかったので、京都会場内でどのような雰囲気だったか気になりました。

感謝

100人も入れる広い会場を提供してくださったグリー株式会社様、大変お世話になりました。BeerTalkの大幅な時間オーバーにも対応して面倒を見てくださったグリー株式会社のいちいさん、大変ありがとうございました。
京都のサテライト会場を提供してくださった京都リサーチパーク株式会社様、ありがとうございました。またその手配、準備などで協力してくださった京都GTUGの方々、@bufferingsさん、お疲れ様です!
今回も開催に関するしきり、Ustやサテライト会場とつなぐための機材や仕組みなどもろもろを準備してくださったスティルハウス佐藤さん、お疲れ様でした。いまだにどんな仕組みで実施したのかわかってません。あまり理解できない自分への説明は必要ないので、次回からもまた頼りにさせていただきます。
BTにて有益な話を聴かせてくださったスピーカーの皆様、QAにて各質問に意見をくださった@higayasuoさん、@najeiraさん、事前に議題やそれへの投票を行ってくださった皆様、会場やTwitterのTLを盛り上げてくださった参加者の皆様、ありがとうございました!次回もよろしくお願いします。

参考資料:過去の参加報告

ajn6の報告を書き忘れてますね…><

2010年4月13日火曜日

marketplace用の #appengine javaアプリの雛形を作ってみました

最近Apps MarketplaceというプラットフォームがGoogleから公開されました。B|CtoB なアプリケーションを登録できるプラットフォームです。アプリケーションの登録・公開方法については@ITさんに記事がありますので、そちらを参考にして下さい。今はまだ開発ベンダ向けのGoogleによる課金のサービスが提供されていませんが、これが開始される時までにそれなりにMarketplace向けのアプリの構築に慣れておきたいものです。私の場合は、モチロン AppEngine を使うことにします。

注意が必要な点として、登録できるアプリケーションには2種類あるって事です。アプリケーションの登録時に「directly installed into Google Apps domains」という選択肢をオンにするかしないか、という違いです。これをオンにすると、GoogleApps使用中のグローバルナビゲーション部分に統合されるアプリケーションを作成することができます。

こうやって統合されている方がユーザとしては使い易いと思われるので、たくさんのユーザに使ってもらうためにもこのタイプのアプリケーションを構築できるようにしておきたいところです。このタイプのアプリとして登録するには OpenIDによるSSO が可能なアプリケーション、という条件があります。しかし、現在のGoogle App EngineのUserServiceでは特定のGoogleアカウントドメインに固定した認証しか対応出来ていません。でも大丈夫です、Marketplace公開日にはSSOアプリとしてのチュートリアルはPHPバージョンしか存在していなかったのですが、いつの間にかAppEngineJavaによるチュートリアルが追加されています。

このサンプルをjarにして依存し、slim3で構築し直した雛形を作成して公開してみました。ライセンスはNYSLで扱って下さい。

使い方

  1. 上記プロジェクトをsvn checkoutやgit svn cloneします。
  2. eclipseを使う方は、checkoutされたフォルダに移動して mvn eclipse:eclipse を実行します。
    • maven-eclipseを連携させるために、eclipse側でM2_REPO変数にmavenのローカルリポジトリを設定しておく必要があります
  3. war/WEB-INF/appengine-web.xml内のそれっぽい変数をそれっぽく編集します。marketplace-sampleって文字を検索すると良いです。
  4. 自分のアプリの本体を実装します
  5. Marketplace用のManifest.xmlのサンプルも一緒にコミットされているので、コメントを参考に適宜いじると良いです。ここでもmarketplace-sampleって箇所を弄りましょう。
  6. デプロイします
  7. marketplaceに登録します

すごい大雑把に書いてしまいましたが、なんとしても appengine で marketplace 向けにアプリを…!って人には手抜きできて良いと思います。また、雛形の中にはOpenIDによるセットアップに続いて実行できるOAuthでの承認も含めていますが、これは本来はOpenIDによる認証とOAuthによる承認を同時に行うべきですので、とりあえずはコメントアウトしています。動作はしますので、誰かHybridに実装し直してくれると大変嬉しいな、とか思ってます。

2010年3月6日土曜日

#appengine javaでcapability serviceを利用する

capabilityサービスを使用すること自体は、今回作ったモジュール(ProtocolBufferの定義それを使用するサンプル)をそのままコピーするなどして使えば簡単にできます。このエントリは、普段JavaでAppEngineを使う人も、Pythonコードを読むと色々役に立つよ、というような内容になってますので、そのあたりに興味が無い人は読んでもあんまり面白くないと思います。Java, Pythonの関係だとその逆も言えるんですけどね。AppEngineは今のところJavaとPythonがありますが、どちらかだけじゃなくて両方触っておくのが一番です。AppEngineJavaを深く触っている人にはSDKのpythonコードもよく参照している人が多いです。

本題

App Engineのサービスがメンテナンスモードの時に、例えばデータストアが読み込み専用になったりします。この時、データストアに対して書き込み操作を行うとCapabilityDisabledExceptionという例外が発生します。これについて、python版ではCapabilitySet(サービス名).is_enabled()のような方法で特定のサービスの稼働状況を調査することができるという事がNick Johnson さんのブログでHandling downtime: The capabilities API and testingというタイトルで紹介されています。失敗させて判断するよりはこういった方法で確認できた方がキレイですね。しかし、JavaにはこのAPIが存在しません。これは残念。しかしPython版のSDKのソースを見ると、capability_serviceというリモートサービスのIsEnabledという機能を呼び出しているだけだという事がわかりますので、これであればJavaであれPythonであれ、言語に関係なくこの機能を使用できるという事がわかります。必要な事はリクエストするバイト配列とレスポンスを受けるバイト配列それぞれについて、どのようにオブジェクトを組み立てれば良いのか?という事だけです。これさえできればJavaからも使用出来そうです。

AppEngineではリモートサービスとのデータのやり取りは全てProtocolBufferでシリアライズされたバイナリを使って行われるので、今回の「capabilityサービスをJavaからも使う」という目的に必要な作業は以下のようになります。ProtocolBufferについては、公式ドキュメントが一番参考になります。

  1. python版のsdkのソースコードから、リクエスト・レスポンスそれぞれのデータ構造を推測する
  2. リクエスト・レスポンスそれぞれのProtocolBuffer定義ファイルを作成する
  3. protocで定義ファイルをコンパイルし、Javaで使用できるクラスを生成する
  4. capabilityサービスを使ってみる!

データ構造を推測する

pythonコードを参考にすると、IsEnabledRequest, IsEnabledResponseというオブジェクトを使う事がわかり、IsEnabledResponseで使用されているCapabilityConfigというオブジェクトも必要そうです。

protocolbufferの定義ファイルを作成する

上記のpythonコードから推測した定義は以下のようなカンジです。完全に正しいかどうかはわかりませんので、もっと厳密に作りたい人はもっと正確な定義を書いてしまえばイイと思います。

message CapabilityConfig {
  enum Status{
    ENABLED = 1;
    SCHEDULED = 2;
    DISABLED = 3;
    UNKNOWN = 4;
  }
  optional string package = 1;
  optional string capability = 2;
  optional Status status = 3;
  optional string internal_message = 4;
  optional string admin_message = 5;
  optional string error_message = 6;
  optional string scheduled_time = 7;
}

message IsEnabledRequest {
  required string pacakge = 1;
  repeated string capability = 2;
  repeated string call = 3;
}

message IsEnabledResponse {
  enum SummaryStatus {
    ENABLED = 1;
    SCHEDULED_FUTURE = 2;
    SCHEDULED_NOW = 3;
    DISABLED = 4;
    UNKNOWN = 5;
  }
  required SummaryStatus summary_status = 1;
  optional int64 time_until_scheduled = 2;
  repeated CapabilityConfig config = 3;
}

Javaのクラスを生成し、使ってみる

protocコマンドでJavaソースを生成して取り込んだ後、私の場合はローカル環境から直接Production環境に接続する方法で試してみました。ソースの該当箇所へのリンクをふたつほど置いておきます。

実行結果は標準出力に出力しましたが、以下のようになりました。

datastore_v3
--start dump of protolbuffer--
summary_status: ENABLED
config {
  package: "datastore_v3"
  capability: "*"
  status: ENABLED
}
config {
  package: "datastore_v3"
  capability: "write"
  status: ENABLED
}
--end dump of protolbuffer--
memcache
--start dump of protolbuffer--
summary_status: ENABLED
config {
  package: "memcache"
  capability: "*"
  status: ENABLED
}
--end dump of protolbuffer--
taskqueue
--start dump of protolbuffer--
summary_status: ENABLED
config {
  package: "taskqueue"
  capability: "*"
  status: ENABLED
}
--end dump of protolbuffer--
user
--start dump of protolbuffer--
summary_status: ENABLED
config {
  package: "user"
  capability: "*"
  status: ENABLED
}
--end dump of protolbuffer--
blobstore
--start dump of protolbuffer--
summary_status: ENABLED
config {
  package: "blobstore"
  capability: "*"
  status: ENABLED
}
--end dump of protolbuffer--
mail
--start dump of protolbuffer--
summary_status: ENABLED
config {
  package: "mail"
  capability: "*"
  status: ENABLED
}
--end dump of protolbuffer--
urlfetch
--start dump of protolbuffer--
summary_status: ENABLED
config {
  package: "urlfetch"
  capability: "*"
  status: ENABLED
}
--end dump of protolbuffer--
xmpp
--start dump of protolbuffer--
summary_status: ENABLED
config {
  package: "xmpp"
  capability: "*"
  status: ENABLED
}
--end dump of protolbuffer--

使ってみた感想

今試した段階では常にENABLEDが帰って来てるので試せませんが、capabilityサービスから返された状態が「SCHEDULED_FUTURE」「SCHEDULED_NOW」の時の「time_until_scheduled」の値などが気になります。
またcapabilityサービスの実行はおよそ15ms-25ms程度のようです。軽いので、フレームワーク側に組み込んでも良さそうですね。

ついでに書いておく

ついでにAppEngineではPython/Javaどっちかいいんだろう?について。これは色々意見があるし自分もよく聞かれるけど、まだブログでそれについて書いたことが無いのでそろそろ書いておこうかと。
自分の結論としては、どっちでもいい、どっちでも触れるならそんなに違いはない、て事ですね。言語自体に好きなものがあるならそっちを使うのがやっぱり楽しい、と思いますし。
ちなみに、比較対象を深く触った・試した事も無いのに「こっちがイイ、あっちはダメ!」とか言う人がよくいるけど、そういうのは恥ずかしい人だなーと感じる。そういう人はそうやって「イイ」と勧める対象をむしろ貶めているかもしれません。せめて、「こっちはイイけど、あっちは知らないからわからない」ならわかるんだけど、深く触ってもいない試してもいない事に対して「ダメ」といっちゃうのは、典型的な「老害」の行動ですね。年とってからそうなるorもうその立場になってしまってる人なんでしょうね。
また、どんなユーザを対象にしたどんなアプリケーションをどれくらいの規模でどういったメンバで作りたいのか?などの具体的な背景がないとどっちとも言えないのですが、それも考えずに断言しちゃう人もどーにかしてるんでしょかね。

2010年2月26日金曜日

slim3と素のJavaで #appengine のspinupを比較してみた

ひがさんの発言で「slim3:1100cpu_ms servlet:720cpu_ms 」ってのがあって、自分のアプリではslim3は大体700-1100cpu_msだったから気になって調べた。

同じApplicationIDで、それぞれ違うバージョンにデプロイし、クライアントから3分おきにcurlしてみた。結果、どちらもspinupは11回、しかも同じタイミングで発生。バージョンが異なれば違うアプリケーションとして動作するけど、同じタイミングでspinupしてるのは偶然…?それは置いといて、肝心のspinup平均はslim3が960cpu_ms, 素Javaが694cpu_msとなった。なんか遅いよな?とか思ったけど、700ms程度で起動しているアプリも今は900ms程度に落ち着いていた。というわけで、slim3と素Javaのspinup時間差はおよそ250-300cpu_ms程度と見ればよさそうですね。ひがさんが書いてたとおりだ、いちいち調査した意味がねぇw

  • slim3
  • 素Java

それよりも、バージョンが違っても同じApplicationIDなら同じ傾向になる…というか同じインスタンスで動作しているのかね?偶然?

2010年2月22日月曜日

#appengine コードラボを開催しました

2/21(日)、クラウドで変わるJava開発 – Java Cloud Meeting Fukuoka 2010 というイベントのおまけイベントとして、BacklogCacooで有名なヌーラボさんの本社をお借りしてAppEngineコードラボを開催しました。

普段東京でやるようなガッツリするかんじのコーディングではなく、8人ほどの参加者の方とまったりのんびりなカンジで作業しました。特徴的だったと思うのは、Google のチュートリアルっぽい事は完全に無視して、HelloWorldをやった後はLowLevelAPIを使った保存・取得を行った事。さらに、その次にslim3-blankをダウンロードしてslim3らしい*-genを使った手順を行う…と見せかけて、slim3-blankはslim3-genとslim3のjarをコピーするだけに使って、Google Plugins for Eclipseで生成したプロジェクトに手動でslim3に必要な設定を行い、slim3-datastoreだけを使ってみたり。

反省点

  • HTMLやらJSPといった、AppEngineとは関係ないところで時間を食いたくないので text/plain をメインにしてやっていた事。やっぱり、地味すぎるし、リンクを置けないなどが不便w 次からはJSPか何かテンプレートをまるっとコピーする方式にしようかな…うーん。
  • MemcacheかURLFetchのどちらかをやっておきたかった。が、15分しか時間が残っておらず断念した。
  • のんびりだったため、がんがんやりたい人にはちょっと間延びしたカンジになってしまったと思う。色々細かいカスタマイズをして時間をうまく使ってくれていたようで、助かりました。うまく立ちまわってくれてありがとうございます。

前日のJava Clound Meetingのために岡山から来て、さらにコードラボにも参加してくださった方もおられて、嬉しかったです。ちょっとゆるめのコードラボもなかなか良いなーと思ったので、またどこかでやる事にします。