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

Java Cloud Meeting Fukuoka 2010

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Java Cloud Meeting Fukuoka 2010

Google App Engine for Java

プラットフォームの勘所

shin1ogawa / appengine ja night

Java Cloud Meeting Fukuoka 2010

Page 2: Java Cloud Meeting Fukuoka 2010

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

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

Page 3: Java Cloud Meeting Fukuoka 2010

プラットフォームの概要

Page 4: Java Cloud Meeting Fukuoka 2010

「Javaで構築されたWebアプリケーション」を、Googleが管理している

「スケールするプラットフォーム上で公開できる」無料のサービス(PaaS)

Google App Engine とは

Page 5: Java Cloud Meeting Fukuoka 2010

Google App Engine とは

「Javaで構築されたWebアプリケーション」を、Googleが管理している

「スケールするプラットフォーム上で公開できる」無料のサービス(PaaS)

「簡単にWebアプリケーションを作成」できたりそれを「簡単にローカルで起動」できたり

ボタンをクリックするだけで「Webアプリケーションを簡単に公開できる」

という開発環境も提供されている

Page 6: Java Cloud Meeting Fukuoka 2010

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

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

Page 7: Java Cloud Meeting Fukuoka 2010

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

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

Page 8: Java Cloud Meeting Fukuoka 2010

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

各処理を担当するサーバが、それぞれスケールする!AppServerの増減をSpinup/Spindownと呼ぶ

Page 9: Java Cloud Meeting Fukuoka 2010

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

• リクエストとレスポンスのサイズ• リクエストは50MB、レスポンスは

• JDKのクラスで使用出来無いクラスが存在する• whitelistが公開されている

• ファイルシステムにアクセスができない• socketを開けない• Threadを作成できない

Page 10: Java Cloud Meeting Fukuoka 2010

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

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

実行時はカスタマイズされたJettyがWebコンテナとして使用されており、それが起動される

Page 11: Java Cloud Meeting Fukuoka 2010

開発・実行環境• Production環境• 管理コンソールが提供されており、リクエストごとのCPU使用率、ログの表示等ができる。• データベースの内容も確認できる。• Timezoneの問題で慣れるまで見づらいけど。

• ひとつのアプリケーションに対して複数のバージョンを登録できて、それぞれのバージョンが完全に別アプリケーションとして使用できる。• データベースは全バージョンで共通。

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

Page 12: Java Cloud Meeting Fukuoka 2010

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

Page 13: Java Cloud Meeting Fukuoka 2010

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

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

Page 14: Java Cloud Meeting Fukuoka 2010

Datastoreサービス

Page 15: Java Cloud Meeting Fukuoka 2010

Datastoreサービスの特徴• 分散KVS(Key Value Store)に分類されるタイプで、RDBとは仕組みが異なる 。

• BigTableに保存される• 書き込みはかなり遅い。読み込みも速いわけではない。• データ件数が何百万件あろうが何千万件あろうが、パフォーマンスが全体の件数に依存しない。

• 基本的には行単位でのACID特性のみ。• ソート順を指定したインデックスを利用した範囲スキャン操作でデータを取得する• SQLみたいなクエリは存在しないと考えておく事!

Page 16: Java Cloud Meeting Fukuoka 2010

Datastoreの用語• Kind...RDBでいう「テーブル」• Entity...RDBでいう「レコード」• Property(属性)...RDBでいう「フィールド」• Index...RDBとほぼ同じ、検索のためのKeyの順序• Key...Entityの主キーの事• Filter...SQLでいうWhere句の条件指定みたいな事• equality filter...演算子で言う”=”でのFilter• inequality filter...”>”, “>=”, “<=”, “<“

• Entity Group...親子関係が構築されたEntityの固まり

“EntityGroup”はRDBには存在しない概念。

Page 17: Java Cloud Meeting Fukuoka 2010

EntityGroupとは• Entity同士の親子構造• RDBでいうRelationとは関係がない。• Java的な継承関係とも関係がない。

• 一回のTranscationで整合性を保って更新できる単位• 一回のTransaction内で複数のEntityGroupに属するEntityを操作することはできない。

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

Page 18: Java Cloud Meeting Fukuoka 2010

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 Fukuoka 2010

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 Fukuoka 2010

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 Fukuoka 2010

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

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

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

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

Page 22: Java Cloud Meeting Fukuoka 2010

Keyの例• 先の例で登場した「Kind:個人 name=橋本」というEntityのKeyは…• “会社(ぬーらぼ)/組織(Cubby)/個人(橋本)”

• 「Kind:組織 name=Cubby」のKeyは…• “ 会社(ぬーらぼ)/組織(Cubby)”

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

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

Page 23: Java Cloud Meeting Fukuoka 2010

インデックスとは• Kind、Property、ソート順を指定して、Entityを並び替えた索引。• 例えば Kind:Person、Property:stand、昇順、• Person/’stand’=’Silver Chariot’• Person/’stand’=‘Star Platinum’• Person/’stand’=’The World’• ...

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

Page 24: Java Cloud Meeting Fukuoka 2010

データの取得…Keyを使う• keyをひとつだけ指定してget• Entityを一件取得できる

• 複数のkeyを指定してget• Entityをまとめて取得できる

• kind名と 親Entityのkeyを指定してget• 指定したKind内の、指定した親Keyに属するEntityを取得できる

• 親Entityのkeyだけを指定してget• 指定した親Keyに属するEntityを全てのKindを横断して取得できる

Page 25: Java Cloud Meeting Fukuoka 2010

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

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

• Joinも無い。

Page 26: Java Cloud Meeting Fukuoka 2010

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

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

• Joinも無い。

クエリではなくてインデックスを使ったレンジスキャン!!

Page 27: Java Cloud Meeting Fukuoka 2010

Datastoreサービス用のAPI• Low Level API(低レベルAPI、LLAPI)• シンプルで正直。Datastoreサービスで利用できる機能にほぼ一対一で対応する。余計な機能は無い。• 特別便利…という機能も無い。

• シンプルなのでパフォーマンスは全APIで最高。• Datastoreを学習するには一番良いAPI。• 属性の操作がいわゆるMap操作に近い。• entity.setProperty(‘hoge’, ‘fuga’)• 属性名を文字列で扱ったり、型安全ではなく少し危険だし、なにより面倒。

Page 28: Java Cloud Meeting Fukuoka 2010

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

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

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

Page 29: Java Cloud Meeting Fukuoka 2010

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

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

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

JDOの状態制御で困っている人を良く見かけるんです(33歳男性)。

JDO?それはないわー(33歳男性)。JDO爆発しろっ…?(33歳男性)。

勝手にトランザクションを開始していて困るんです(33歳男性)。

Persistent?Putじゃなくて?(33歳男性)。

Page 30: Java Cloud Meeting Fukuoka 2010

Datastoreサービス用のAPI• Slim3(公式ではなくSDKにも含まれていないが)• AppEngine専用のフレームワーク。• LowLevelAPIとほぼ同じパフォーマンスを発揮

• HotReloadが使用できるController等の仕組みもあるが、Datastoreだけで使う事もできる。

• 「Global Transaction」という、複数のEntity Groupを対象にTranscation処理する機能。

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

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

Page 31: Java Cloud Meeting Fukuoka 2010

Datastoreサービスの学習方法• EntityGroupを理解する。• インデックスを理解する。今なら資料も豊富。• APIについてどれを使うかは好みの問題だが、まずLow Level APIで軽くひととおりの操作を勉強し、その後Slim3、JDO/JPA…という順序がおすすめ。

• 今はかなり情報が豊富に存在するので、先駆者のハマリっぷりを後から追う。• slim3のドキュメントが一番充実している• “appengine”や”GAE”と言うキーワードで検索• “#appengine”ハッシュタグでつぶやく|検索

Page 32: Java Cloud Meeting Fukuoka 2010

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

• 集計するような導出項目、カウンタは別途保持する• 更新時に計算結果や中間結果を計算しておく

• ジョインが必要ならジョイン済みのKindを作成する• 検索要件をよく把握する。インデックスが作れないクエリは工夫が必要なる。

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

EntityGroupの設計と非正規化が肝!

Page 33: Java Cloud Meeting Fukuoka 2010

その他のサービス

Page 34: Java Cloud Meeting Fukuoka 2010

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

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

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

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

Page 35: Java Cloud Meeting Fukuoka 2010

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

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

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

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

Page 36: Java Cloud Meeting Fukuoka 2010

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

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

Page 37: Java Cloud Meeting Fukuoka 2010

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

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

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

Page 38: Java Cloud Meeting Fukuoka 2010

まとめ

Page 39: Java Cloud Meeting Fukuoka 2010

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

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

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

Page 40: Java Cloud Meeting Fukuoka 2010

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

Page 41: Java Cloud Meeting Fukuoka 2010

予備のスライド

Page 42: Java Cloud Meeting Fukuoka 2010

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

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

Page 43: Java Cloud Meeting Fukuoka 2010

リソース使用量の上限

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

Page 44: Java Cloud Meeting Fukuoka 2010

“Billing”の設定

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

Page 45: Java Cloud Meeting Fukuoka 2010

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

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