43
Google App Engine for Java プラットフォームの勘所 shin1ogawa / appengine ja night Java Cloud Meeting Tokyo 2010

Java cloud-meeting-2010tokyo-shin1ogawa

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Java cloud-meeting-2010tokyo-shin1ogawa

Google App Engine for Java

プラットフォームの勘所

shin1ogawa / appengine ja night

Java Cloud Meeting Tokyo 2010

Page 2: Java cloud-meeting-2010tokyo-shin1ogawa

shin1ogawa と申しますGoogle, AppEngine, Apps, Java, Eclipse, Maven, Hudson, 構成管理... 等を主食とするJava屋です。

appengine ja night という「Google App Engineの実践的な情報交換を行おう!」という事を目的としたコミュニティで、主に東京で月に一回くらいのペースで勉強会を開催しています。かなり実践的な情報交換が行われており、Twitterで #ajn8 等のハッシュタグでtsudaられる事が多いです。まとめサイトもひっそりと準備中です。

Page 3: Java cloud-meeting-2010tokyo-shin1ogawa

プラットフォームの概要

Page 4: Java cloud-meeting-2010tokyo-shin1ogawa

Googleが管理している「自動的にスケールアウトするプラットフォーム上に、 Java/Pythonで構築されたWebアプリケーションを配置し公開する事ができる」サービス。

Google App Engine とは

Page 5: Java cloud-meeting-2010tokyo-shin1ogawa

Google App Engine とはGoogleが管理している「自動的にスケールアウトするプラットフォーム上に、 Java/Pythonで構築されたWebアプリケーションを配置し公開する事ができる」サービス。

開発環境も提供されていて、「簡単にWebアプリケーションを作成」でき「簡単にローカルだけで動作確認」でき「簡単にWebアプリケーションを公開」できる。単体テストのサポートも充実している。

Page 6: Java cloud-meeting-2010tokyo-shin1ogawa

どんな用途で使えるか• Webサービスを作って公開したい• インパクトが大きくなりがちなキャンペーンサイト• サーバを持ちたくない企業の自社サイト• サーバを持ちたくない企業の小さめの業務アプリ• GoogleApps利用企業のAppsを拡張するサービス• Java屋さんが得意とするデカイ業務アプリ• →不具合発生やサービス停止時に深刻な被害が出るようなアプリケーションへの適用は難しい

…色々考えられるけど、スタートは無料・簡単!やってみれば色々わかってきます!

Page 7: Java cloud-meeting-2010tokyo-shin1ogawa

プラットフォームのふるまい

最初に“Frontends”と呼ばれるサーバが静的リクエスト、動的リクエストを判断して振り分ける。

Page 8: Java cloud-meeting-2010tokyo-shin1ogawa

プラットホームの制限• 30秒制限…これが一番有名?• リクエストがFrontendsに届いてから30秒が経過した時点で例外が発生する

• 各種サイズの制限• リクエスト、レスポンス、ファイルは10MBまで• ファイル数は3000個、全体で150MBまで• JDKのクラスで使用出来無いクラスが存在する• whitelistが公開されている• ファイルシステムにアクセスができない• socketを開けない

Page 9: Java cloud-meeting-2010tokyo-shin1ogawa

開発・実行環境• 開発環境• SDKが提供され、ant用のスクリプトが提供される。コマンド一発で実行、デプロイができる。

• eclipseプラグインも提供されており、ボタンをぽちるだけでプロジェクトの作成、実行、デプロイができる。AppEngine用プロジェクトのファイル構成は、特殊な設定ファイルがいくつかある程度で、通常のJavaWebアプリケーションとあまり違いはない。

Page 10: Java cloud-meeting-2010tokyo-shin1ogawa

開発・実行環境• 実行環境(Production環境)• 管理コンソールが提供されており、リクエストごとのCPU使用率、ログの表示等ができる。• データベースの内容も確認できる。• Timezoneの問題で慣れるまで見づらいけど。• ひとつのアプリケーションに対して複数のバージョンを登録できて、それぞれのバージョンが完全に別アプリケーションとして使用できる。• データベースは全バージョンで共通。

リモートデバッグはできないので、ログベースで確認。

Page 11: Java cloud-meeting-2010tokyo-shin1ogawa

提供されるサービス(機能)の紹介

Page 12: Java cloud-meeting-2010tokyo-shin1ogawa

アプリケーションから利用できる機能• Datastoreサービス• Memcacheサービス• TaskQueue, ScheduledTaskサービス• URLFetchサービス• Mail送信・受信サービス• Blobstoreサービス(有料オプション適用時のみ)• Userサービス• XMPPサービス• Imageサービス

色々な機能が「~サービス」として提供されている

Page 13: Java cloud-meeting-2010tokyo-shin1ogawa

Datastoreサービス

Page 14: Java cloud-meeting-2010tokyo-shin1ogawa

Datastoreサービスの特徴• 分散KVSなのでRDBとは仕組みが異なる。• スキーマを持たない→ソフトスキーマ• 裏側ではBigtableが使用されている• 書き込みはかなり遅い。読み込みも速いわけではない。• 検索パフォーマンスが全体の件数に依存しない。• BigTable→基本的には行単位でのACID特性のみ。• Bigtableを拡張した機能を提供している。• ソート順を指定したインデックスを利用したスキャン操作でデータを検索することができる• SQLみたいなクエリは存在しないと考えておく事!

Page 15: Java cloud-meeting-2010tokyo-shin1ogawa

Datastoreサービスの特徴• ソフトスキーマ• key=shin1, value=[age=25, weight=55.0]• key=hsmt, value=[age=34, place=fukuoka]• Bigtableを拡張した機能を提供• 複数行をまとめた単位に対する操作に対する一貫性の保証→Entity Group

• Value内の属性(フィールド)の値のソート順を保存し、そのデータをスキャンすることでクエリのような機能を提供→Index

Page 16: Java cloud-meeting-2010tokyo-shin1ogawa

Datastoreの用語• Kind...RDBでいう「テーブル」• Entity...RDBでいう「レコード」• Property...RDBでいう「フィールド」• Index...RDBとほぼ同じ、検索のためのフィールドの値のソート順序

• Key...Entityの主キー• Filter...SQLでいうWhere句の条件指定みたいな事• equality filter...演算子で言う”=”でのFilter• inequality filter...”>”, “>=”, “<=”, “<“

Page 17: Java cloud-meeting-2010tokyo-shin1ogawa

EntityGroupとは• Entity同士の親子構造• RDBでいうRelationとは関係がない。• Java的な継承関係とも関係がない。• EntityのKey内に親EntityのKeyを含む• 一回のTranscationで整合性を保って更新できる単位• 一回のTransaction内で複数のEntityGroupに属するEntityを操作することはできない。

• 異なるTransactionが同時にひとつのEntityGroupを操作しようとした場合は、後からcommitした方がエラーになる(楽観的排他制御)。

Page 18: Java cloud-meeting-2010tokyo-shin1ogawa

EntityGroupの例

• 会社Kind: name=トップゲート• 組織Kind: name=システム部• 個人Kind: name=小川

• 会社Kind: name=ぬーらぼ• 組織Kind: name=Cubby部• 個人Kind: name=橋本• 個人Kind: name=懸

3種類のKind、7EntityでふたつのEGを構成した例

Page 19: Java cloud-meeting-2010tokyo-shin1ogawa

EntityGroupの例

• 会社Kind: name=トップゲート• 組織Kind: name=システム部• 個人Kind: name=小川

• 会社Kind: name=ぬーらぼ• 組織Kind: name=Cubby部• 個人Kind: name=橋本• 個人Kind: name=懸

3種類のKind、7EntityでふたつのEGを構成した例

EntityGroupが別なので「小川」「橋本」を一回のTransactionで更新出来無い。

Page 20: Java cloud-meeting-2010tokyo-shin1ogawa

EntityGroupの例

• 会社Kind: name=トップゲート• 組織Kind: name=システム部• 個人Kind: name=小川

• 会社Kind: name=ぬーらぼ• 組織Kind: name=Cubby部• 個人Kind: name=橋本• 個人Kind: name=懸

3種類のKind、7EntityでふたつのEGを構成した例

同じEntityGroupに属するので「橋本」「懸」を別のTransactionから同時に更新出来無い(排他制御される)

Page 21: Java cloud-meeting-2010tokyo-shin1ogawa

EntityGroupでは無い例

• 会社Kind: name=ぬーらぼ• 組織Kind: name=システム部, 会社=Key(ぬーらぼ)

• 個人Kind: name=橋本, 組織=Key(システム部)

上記の例だと、それぞれのEntityがそれぞれのEntityのKeyをPropertyに保持して参照しているだけで、親子関

係とは呼ばない。Entity Groupは、子EntityのKeyの中に親Entityの

Keyを含む事で構成する!

Page 22: Java cloud-meeting-2010tokyo-shin1ogawa

Keyとは• Entityを一意に識別するための主キー• アプリケーションIDと、親EntityのKey、Kind名、数値id, または文字列のname値、で構成される。• 数値id, または文字列のname値 はEntityGroup内でユニークになる。• Kind内でユニークではない

• EntityGroupで親子関係を構成した場合は、子EntityのKeyは親EntityのKeyを含む。

• 構成要素をエンコードした文字列として保存される。

EntityGroupはEntityのKeyを使って構成される

Page 23: Java cloud-meeting-2010tokyo-shin1ogawa

Keyの例• 先の例で登場した「Kind:個人 name=橋本」というEntityのKeyは…• “会社(ぬーらぼ)/組織(Cubby)/個人(橋本)”• 「Kind:組織 name=Cubby」のKeyは…• “ 会社(ぬーらぼ)/組織(Cubby)”• 別の会社や組織に「Kind:個人 name=橋本」が存在しても、親EntityのKeyである“会社(ぬーらぼ)/組織(Cubby)”が重複しない限り、ユニークになっている。

RDBのようなフィールド間の値を使った関連とは異なり EntityGroupはEntityのKeyを使って構成される

Page 24: Java cloud-meeting-2010tokyo-shin1ogawa

インデックスとは• Kind、Property、ソート順を指定して、Entityを並び替えた索引で、インデックステーブルという場所に保存される。• 例えば Kind:Person、Property:stand、昇順、• Person/’stand’=’Silver Chariot’• Person/’stand’=‘Star Platinum’• Person/’stand’=’The World’

• この索引の特定の範囲を指定して、複数件のEntityを取得する=インデックスを使ったスキャン複数のPropertyを指定したり、色々種類がある。超重要な要素なので、必ず最初に勉強すること!

Page 25: Java cloud-meeting-2010tokyo-shin1ogawa

クエリ• Kind名, 属性名, フィルタ種別, 属性値を指定する• フィルタ種別: ’<‘, ‘<=’, ‘==’, ‘>=’, ‘>’, ‘!=’, ‘IN’• Likeは無い。前方一致は可能(startsWith()) • 複数の条件はAnd接続のみ可能• 複数の属性に対して条件を指定する事ができるが、inequality filter(‘==’以外)を適用できるのはひとつの属性だけ

• max()とかmin()とかcount()とか、RDBでは当たり前の便利な関数は存在しない。

• Joinも無い。

Page 26: Java cloud-meeting-2010tokyo-shin1ogawa

クエリ• Kind名, 属性名, フィルタ種別, 属性値を指定する• フィルタ種別: ’<‘, ‘<=’, ‘==’, ‘>=’, ‘>’, ‘!=’, ‘IN’• Likeは無い。前方一致は可能(startsWith()) • 複数の条件はAnd接続のみ可能• 複数の属性に対して条件を指定する事ができるが、inequality filter(‘==’以外)を適用できるのはひとつの属性だけ

• max()とかmin()とかcount()とか、RDBでは当たり前の便利な関数は存在しない。

• Joinも無い。

検索=インデックスを使ったスキャンなので、インデックスが作れなければ検索出来ない!インデックスを作れるかどうか?=クエリできるかどうか?

Page 27: Java cloud-meeting-2010tokyo-shin1ogawa

Datastoreサービス用のAPI(1)• Low Level API(低レベルAPI、LLAPI)• シンプルで正直。Datastoreサービスで利用できる機能にほぼ一対一で対応する。余計な機能は無い。• 特別便利…という機能も無い。• シンプルなのでパフォーマンスは全APIで最高。• Datastoreを学習するには一番良いAPI。• 属性の操作がいわゆるMap操作に近い。• entity.setProperty(‘hoge’, ‘fuga’)• 属性名を文字列で扱ったり、型安全ではなく少し危険だし、なにより面倒。

Page 28: Java cloud-meeting-2010tokyo-shin1ogawa

Datastoreサービス用のAPI(2)• JDO/JPA• JDOは非常にWeb上のドキュメントが多い。JPAはWeb上のドキュメントが少ないが、ユーザも多いだろうしこれからはドキュメントも増えるかもしれない。

• DatastoreをRDBっぽく扱おうとするAPIで、一見RDBかと錯覚するほど普通に使えそうに見える。

• AppEngineのデータストアをかなり隠蔽してしまっていて、先程までの説明の内容を理解せずに使うとほぼ必ずハマる!

Page 29: Java cloud-meeting-2010tokyo-shin1ogawa

Datastoreサービス用のAPI(3)• Slim3(公式ではなくSDKにも含まれていないが)• AppEngine専用のフレームワーク。• LowLevelAPIとほぼ同じパフォーマンスを発揮• ものすごく作りこまれたテストサポートの機能• Datastoreだけで使う事もできる。• 「Global Transaction」という、複数のEntity Groupを対象にTranscation処理する機能。

• APTを利用したタイプセーフクエリ、リフレクションを使わないEntity-POJOマッピング。

• 自動リトライ等、気の利いた便利な機能が満載。

Page 30: Java cloud-meeting-2010tokyo-shin1ogawa

Datastoreサービスの学習方法• EntityGroupを理解する。• インデックスを理解する。今なら資料も豊富。• まずLow Level APIで軽くひととおりの操作を勉強し、その後Slim3、興味があればJDO/JPA…という順序がおすすめ。

• 先駆者のハマリっぷりを後から追う。• slim3のドキュメントが充実している。• “appengine”や”GAE”と言うキーワードで検索• “#appengine”ハッシュタグでつぶやく|検索

Page 31: Java cloud-meeting-2010tokyo-shin1ogawa

スキーマの設計について• どれとどれをEntityGroupとして構成するか(ひとつのTransactionで処理したい対象は?)、が重要

• 集計するような導出項目、カウンタは別途保持する• 更新時に計算結果や中間結果を計算しておく• ジョインが必要ならジョイン済みのKindを作成する• 検索要件をよく把握する。インデックスが作れないクエリは工夫が必要となる。

• Shardingカウンタ、ページング、など公開されているパターンを先に知っておく

IndexとEntityGroupの理解が肝!

Page 32: Java cloud-meeting-2010tokyo-shin1ogawa

まとめ

Page 33: Java cloud-meeting-2010tokyo-shin1ogawa

まとめ• 色々制限があるように感じると思うが、スケールする事が前提となっているため、従来のアプリケーションとは別物だから仕方ない。

• むしろ、制限と捉えるのではなく制約として受け止め、「制約を正しく理解する」事で、新しい時代の設計・実装手法を学ぶための養成ギブスで腕を磨く機会としよう。

• ちょっとしたWebサービスを公開するには絶好のプラットフォームで、そんなに難しいものでもないので、是非楽しんでください!

Page 34: Java cloud-meeting-2010tokyo-shin1ogawa

ご清聴ありがとうございました

Page 35: Java cloud-meeting-2010tokyo-shin1ogawa

予備のスライド

Page 36: Java cloud-meeting-2010tokyo-shin1ogawa

Memcacheサービス• その名の通りメモリにデータをキャッシュする• 保存する時にKeyとValueを指定して、取得する時はKeyを指定する。

• 全インスタンスから参照できるMapのようなイメージ• クエリ結果等をキャッシュしておくと、Datastoreに同じクエリを発行するよりも高速に値を取得できる

• ドキュメントには「キャッシュした情報が必ず存在する保障は無い」と書かれているので、存在することを前提とした実装をしてはいけない。

Webアプリケーションでは必須ともいえる

Page 37: Java cloud-meeting-2010tokyo-shin1ogawa

TaskQueueサービス• 処理をキューに追加すると、バックグラウンドで次々にキューから取り出されて非同期に処理が実行される• 実行する処理は、Webハンドラ(Servlet等)として実装する

• キューに追加する側は、HttpRequestとして処理にパラメータを渡す

• 処理が失敗すると、成功するまで延々とリトライされる• Webハンドラとして実装された処理側が200(OK)以外を返すとエラーとして扱われる

べき等(なんど実行されても平気)に実装する必要がある

Page 38: Java cloud-meeting-2010tokyo-shin1ogawa

TaskQueueサービスの例• アクセスカウンタの更新を、リクエストがあったタイミングでは処理せずに、更新処理をQueueに入れて非同期に処理する。• レスポンス速度が少しでも早くなるし、成功するまでリトライされるのでいつか必ず更新が成功する

• 複数のデータのグループ(区分値とか)を対象に集計処理などを行う際に、区分ごとにTaskを作成しQueueにどんどん追加する• 従来のアプリケーションでいうバッチ処理を並列実行するようなイメージ

Page 39: Java cloud-meeting-2010tokyo-shin1ogawa

ScheduledTaskサービス(Cron)• 一定間隔または指定した時刻に処理を実行する• TaskQueue同様、実行する処理はWebハンドラ(Servlet等)として実装する

• TaskQueueの例であった「バッチ処理」を起動するトリガーとして使い、処理内で子TaskをQueueに追加するという使い方が多い• 時間がかからない・処理対象データが少ない場合はScheduledTask内で処理を実行しても良い

TaskQueueと違い、エラー終了でもリトライされない

Page 40: Java cloud-meeting-2010tokyo-shin1ogawa

アカウント取得の際の注意http://code.google.com/intl/ja/appengine/kb/sms.html

SMS認証が必要だが、認証コードが書かれたメールを受け取れないキャリアもある模様。その場合は問い合わせフォームから問い合せるとすんなり対応してもらえる…らしい。

Page 41: Java cloud-meeting-2010tokyo-shin1ogawa

リソース使用量の上限

24時間で消費量がリセットされるものがほとんど。

Page 42: Java cloud-meeting-2010tokyo-shin1ogawa

“Billing”の設定

こんなカンジで「一日の上限額」を決めて、各リソースごとに細かく振り分ける事ができます。

Page 43: Java cloud-meeting-2010tokyo-shin1ogawa

SpinUpと”10秒制限”• リクエストを捌く際、インスタンスひとつにつき同時に1リクエストだけしか処理されない。• インスタンス数を超えるリクエストが到着した場合は、Frontendsのリクエストキューにリクエストが貯められる。キューの中で10秒経過したリクエストは「Request aborted...」というエラーで返る。

• 例)インスタンスが存在しない状態でリクエストが3つ到着→一つ目のリクエストでSpinup発生。• spinupに15秒かかった場合、10秒経過時にキュー内の2つのリクエストはエラーで返ってしまう。