Googleを支えるクラウド技術 スティルハウス 佐藤一憲
アジェンダGoogle App Engineとは分散KVSとBigtable DatastoreサービスDatastoreのクエリ
自己紹介スティルハウス 佐藤一憲twitter: @kazunori_279ブログ: 「スティルハウスの書庫」Web: http://www.sth.co.jp/コミュニティ活動appengine ja nightGoogle API Expert (App Engine)主な業務開発: Adobe Flex/AIR、Rails、GAE/Jテクニカルライティングや翻訳(ペンネーム吉川和巳)セミナー講師など
Google App Engineとは
Google App EngineとはGoogle App EngineとはWebアプリホスティングサービス自分のアプリをGoogleのクラウド上で運用できる2008年4月にPython版リリース2009年4月にJava版リリース
Google App Engineとは利用状況(2010年12月現在)10億PV/日(mixiと同程度)開発者の増加は10万人/月アプリの増加は15万件/週
App EngineのすごいところApp Engineのすごいところ「2ケタ安」の圧倒的な低コストどこまでもスケール+高可用性開発・運用環境が構築不要
「2ケタ安」の低コスト無償分と有償分初期コストはゼロ無償分だけでも“400万PV/月相当を運用可能”
「2ケタ安」の低コスト「ふにゃもらけ」の事例MixiアプリをApp Engineで提供1日600万PV以上(月1.8億PV相当)Googleからの請求は1日$15(月額4万相当)スティルハウス担当事例従来はデータセンターのサーバーを1台使用400万件のデータ(約11GB)をApp Engine移行月額$4サーバー管理者が不要に
どこまでもスケール+高可用性Googleのクラスタ環境を簡単に利用できる 自動クラスタリングによる負荷分散と高可用性負荷状況に応じてApp Serverを動的に増減 アプリ間の隔離性を維持、個々のアプリの安全性とパフォーマンスを確保BigtableのスケーラビリティRDBにつきもののスケーラビリティ上限がないテーブル間の結合(join)ができないトランザクションの整合性保証の範囲を限定しているApp Engineの全アプリのデータは、1つのBigtableテーブルに格納されている
スケールアウト事例ホワイトハウスの"Open For Questions" 2日間だけ提供された投票サイト その結果を受けてオバマ大統領が記者会見を行った 10万件の質問と360万件の投票を受け付けた ピーク時には毎秒700回のクエリを実行した App Engineをout of boxで使用Google Moderatorのソースをベースに、ホワイトハウス側の開発者がチューンしてデプロイ。Google側による特別な作り込み等は行っていない App Engine上の他のアプリには一切影響なし
スケールアウト事例"Open For Questions"のトラフィック推移
開発・運用環境が構築不要統合開発環境を提供 サーバーの構築や管理が不要。デプロイが容易管理コンソールを提供ログ管理、管理コンソールや各種ツールを提供
Google App Engine Stackの構成Google App Engine Stackの構成
App Engine Stackの構成要素App Engineが提供するAPI
App ServerについてApp Serverのサンドボックスによる制限HTTPリクエスト処理は最大30秒までApp Engine最大の制約のひとつ時間のかかる処理はTask Queueでファイルシステムへの書き込み外部サーバへのソケット接続HTTPリクエスト送信は可能スレッド生成ガベージコレクション実行やシステム停止カスタムクラスローダの利用
App Serverのスケールアウト高負荷時の自動デプロイ 高負荷状態が一定時間続くと、新しいApp Serverが追加され負荷分散し、負荷が低くなると削除される  アプリが受けられる負荷に上限はあるか? 同時30リクエストの制限リクエスト処理時間に応じてスループット上限は変化それ以上の負荷を扱いたい場合はGoogleに依頼する。アプリごとにsafety limitを解除できる
分散KVSとBigtable
分散KVSとは分散KVSとは「キー」と「値」のペアを保持する分散データストア「Map」や連想配列のようなもの
分散KVSとは各社のクラウド向け分散KVSGoogleBigtableAmazon Web ServiceAmazon DynamoマイクロソフトAzureAzure Storage Service楽天「ROMA」オープンソース実装Facebookによる「Cassandra」など
分散KVSの長所短所メリットスケールアウト構成を取りやすく、スケーラビリティが頭打ちにならない高可用性を実現しやすいデメリットデータ全体を対象としたトランザクションの整合性確保が困難RDBのような高度なクエリやテーブルの結合(join)が困難
分散KVSとRDB分散KVSとRDBの長所短所
RDBはスケールしない?RDBのスケーラビリティ強化手段RDBサーバーのスケールアップ大型サーバーへの載せ替えDBのレプリケーションやシャード(パーティション)分割によるクラスタ構築分散キャッシュ(Oracle RACやmemcachedなど)によるクラスタ構築->いずれも複雑で高コストなソリューション数千万~数億円以上RDBのスケールアウトは原理的に困難
RDBとCAP定理CAP定理UC Berkley大のEric Brewer教授が2000年に発表Consistency, Availability, Partition分散環境(P)では整合性(C)と可用性(A)間でトレードオフ発生
BASEトランザクションBASEトランザクションCAP定理を反映した分散環境での“ゆるい”トランザクションBasically Available可用性の高さを優先する(悲観排他より楽観排他)Soft-State and Eventually Consistent状態の一時的な不整合を許容する結果的に整合性が確保される仕組みにしておく例:DNS、Google WaveのOT
分散KVSとCAP定理分散KVSではACID保証の範囲を制限、可用性を確保
クラウドによる全体最適化分散KVSの「制約」こそ「クラウドのキモ」整合性が限定、結合できない、etc...->アプリが分散環境に対応するための必須条件クラウドによる全体最適化分散環境に対応した多数のアプリを、きわめて効率よく集約(コンソリデーション)できる独立したOS、仮想マシン、DBが不要クラウドという巨大単一コンピュータへの融合「2ケタ安」のコストを実現無制限のスケーラビリティと高可用性を安価に提供メインフレームへの回帰?
クラウドによる全体最適化
Bigtableの概要Bigtableとは巨大分散データストアリレーショナルモデルに基づくRDBではないいわゆる分散Key-value Store(KVS)やNoSQL膨大な数の汎用サーバーをつなげてペタバイト規模のデータを扱えるよう設計現在およそ数PB全世界36か所以上のデータセンターに配置された数万台~数10万台のサーバーに分散Googleクラウドの「虎の子」
Bigtableの概要Bigtableの歴史およそ7人年の開発作業を経て、2005年4月からプロダクション利用を開始 Googleの70以上のプロジェクトが利用 検索, GMail, Analytics, Finance, Earth, YouTube, MapなどBigtableの特徴実用上、無制限のスケーラビリティサーバー冗長化による高可用性
無制限のスケーラビリティ実用上はスケーラビリティに上限がないテーブルの規模が100件でも、数1000万件でも、個々の行の読み書きは数10 ms程度で完了膨大な数のユーザーがBigtableに同時にアクセスしても、レスポンスの低下は発生しない一般的なWebアプリケーションの大半では、RDBサーバーがボトルネックとなってデータ量やアクセス件数の増加にともないレスポンス時間が低下Bigtableを使ったWebアプリケーションではそれが皆無
サーバー冗長化による高可用性Google独自の分散ファイルシステム「Google File System(GFS)」異なるラックに設置された3台以上のサーバーにコピーサーバー障害によってデータが失われる可能性はきわめて低いいずれか1台のサーバーが停止しても他の2台のいずれかから同じデータを瞬時に取得Bigtableのサービスを構成するサーバー群はすべてが冗長化SPoF(Single Point of Failure)を排除Oracle RACなどのハイエンドのRDBクラスタに匹敵する高可用性
Bigtableの構成要素 Bigtableのテーブル Bigtableのテーブルは、「分散化された多次元ソートマップ」 簡単に言うと、ソート済みのExcel表のようなもの 個々のセルは履歴を残せる(multidimensional)
Bigtableの構成要素 Bigtableのテーブル テーブルの実体は、巨大なkey-value store キー:行キー+カラムキー+タイムスタンプ行キーは最大64KBまで(大半は10~100バイト) 行キーの辞書順でソートされている 行単位のCRUDはアトミックに実行 複数行にまたがる更新処理は原子性が保証されない 古い履歴データや削除された行は、自動的にGC
BigtableにできることBigtableにできること キーを指定した行単位のCRUD 行単位のACID特性が保証される 2種類のスキャン: prefix scan: キーの前方一致検索で複数行を一括取得 range scan: キーの範囲指定検索で複数行を一括取得 ソート済みなので高速に実行できる Bigtableではカラムの値に基づく検索は一切実行できない!
Bigtableにできること
Bigtableの内部構造Googleの典型的なクラスターノード構成
Bigtableの内部構造個々のノードの基本構成 Intelベースの安いPC Linux OS Schedulerスレーブ Schedulerマスターの指示に従ってノード上に各種サービスをデプロイする GFSチャンクサーバー GFSのチャンク(データ)を保存する タブレットサーバー Bigtableのタブレットを管理する
Bigtableの内部構造Bigtableクラスター全体を管理するサービスSchedulerマスター 各ノードに各種サービスをデプロイする Chubby 分散ロックサービス GFSマスター GFSチャンクサーバー群を統括する Bigtableマスター tablet server群を統括する
Bigtableの内部構造Bigtableクラスター 複数のBigtableテーブルからなるクラスター 2006年8月時点では、388のBigtableクラスターと24,500のタブレットサーバーが稼働中タブレット Bigtableのテーブルを分割したもの テーブルの内容はタブレット単位で各タブレットサーバーに分散保存される 1つのタブレットは100~200MB程度のデータを保存。それ以上になると分割される 1台のタブレットサーバーは100以下のタブレットを保存
Bigtableの内部構造タブレット 復旧が高速1台がダウンしても、その100個のタブレットは他の100台のサーバーが保有している Bigtableマスターが負荷分散を管理高負荷のサーバーからタブレットを移動
タブレットサーバーのメカニズムタブレットサーバーの階層問い合わせ
タブレットサーバーのメカニズムタブレットサーバーの検索 あるキーのデータを取得するときクライアントはタブレットサーバーのIPアドレスを取得DNSライクな階層問い合わせ 検索の流れブートストラップとなるChubbyサービスにアクセスMETADATAタブレットを持つタブレットサーバーのIPアドレスを取得METADATAタブレットには、各キーに対応するタブレットサーバーのIPが記録されている
タブレットサーバーのメカニズムタブレットサーバーの検索 タブレットサーバーの検索には、最大で3回のネットワーク通信が必要通常はクライアント側にMETADATAタブレット内容がキャッシュされており、クライアントはタブレットサーバーに直接接続できる
キャッシュ管理とディスクアクセスBigtableのキャッシュ構造コミットログテーブルへのアクセスminor compaction(ディスクにflush)memtable (キャッシュ)major compaction(ゴミファイルをGC)SSTable (ディスク上のファイル)GFSGFSGFS
キャッシュ管理とディスクアクセスmemtableによるキャッシュ管理memtableは、タブレットにコミットされた更新内容を記録するソート済みのバッファ 個々の更新処理はディスク上のコミットログに記録され、更新内容はmemtableに記録される
キャッシュ管理とディスクアクセスマイナーコンパクション memtableがいっぱいになると、その内容がSSTableにフラッシュされる(OracleのDBWR+チェックポイントと同様)
キャッシュ管理とディスクアクセスSSTableによるディスク保存SSTableとは、memtableの内容保存に利用されるファイルフォーマット ソート済みのイミュータブル(変更不可)なマップ(key-valueペア) イミュータブルなのでファイルアクセス時のロックが不要、同時アクセスを効率的に扱える コピーオンライトですばやくタブレットを分割できる
キャッシュ管理とディスクアクセスメジャーコンパクション削除されたデータがゴミとして残るので、マーク&スウィープGCを実行する (PostgreSQLのvacuumと同様)
GFSの利用GFSによるディスクへの書き込み GFS(Google File System)とは、SSTable等のファイル保存に用いられるファイルシステム ファイルは必ず3台以上のサーバーに書き込み ローカルのGFSチャンクサーバーが空いていれば、そこに1つを書き込み 残り2つは、離れた場所(少なくとも同じラックではない場所)のGFSチャンクサーバーに書き込み
GFSの利用GFSによるデータのレプリケーション
GFSの利用GFSによるディスクへの書き込み タブレットが移動しない限り、タブレットサーバーはローカルのGFSチャンクサーバーにアクセス負荷分散のためタブレットが移動すると、データは残したままタブレットのみ移動 バイナリアップグレード時などに、できるだけローカルに置くようにデータを再配置
Datastoreサービス
DatastoreサービスとはApp Engineにおけるデータ保存サービスBigtable上に実装されているDatastoreサービスでできることオブジェクトのCRUD(Create, Read, Update, Delete)エンティティグループ単位でACIDを確保(後述)オブジェクトのクエリ(検索)JDOQLまたはGQLを使用
DatastoreサービスとはJDO APIによるオブジェクト保存の例        PersistenceManager pm = PMF.get().getPersistenceManager();        Employee e = new Employee("Alfred", "Smith", new Date());        try {            pm.makePersistent(e);        } finally {            pm.close();        }
Datastore用語Datastore用語と既存用語のおおまかな対比カインド(kind)クラス/テーブルエンティティ(entity)オブジェクト/レコードプロパティ(property)フィールド/カラムキー(key)オブジェクトID/プライマリーキー
エンティティテーブルエンティティテーブルとは エンティティを保存するテーブルApp Engine内のすべてのエンティティテーブルが1つのBigtableテーブルに格納されている個々のエンティティは、キーで識別キーの辞書順でソートされている個々のエンティティのプロパティ内容は、すべてBigtableの1つのカラムにシリアライズされて格納 Protocol Buffer形式で保存される
キーキー アプリID+パス(カインド名+IDまたはキー名)IDは自動採番エンティティグループなし:カインド内でユニークエンティティグループあり:エンティティグループ内でユニークキー名はアプリ側で設定ユニークにする必要があるエンティティのキーは変更できない表記例Foo(25)カインド名+ID(アプリIDは表示されない)agR0ZXN0cgkLEgNGb28YGQwprotocol buffer+BASE64
プロパティプロパティ variable properties エンティティごとにプロパティの数や種類を変えられる「プロパティがない」と「プロパティがnull」は区別されるheterogenous property types エンティティごとにプロパティの型を変えることができる (GAE/Jでこれを使えるかは不明)
プロパティの特徴Datastoreのプロパティの特徴 multiple value properties (MVP) 1つのプロパティにListやtupleを保存できるシリアライズして保存されるクエリの例:name == 'Foo' List内のいずれか1つの値がFooならtrueになる非正規化や設計の最適化に活用できる1:N関連の代わりに使う(非正規化)ジョインテーブルの代わりに使うSerializableオブジェクトを格納可能
DatastoreのパフォーマンスDatastoreの性能は、エンティティの数とは無関係 保存されているエンティティが1件でも、1000件でも、1000万件でも、パフォーマンスに変化はない エンティティへの読み書き速度エンティティの読み込み:平均数10ms程度エンティティの更新:平均100ms程度個々のエンティティの更新処理は遅いアプリケーションのパフォーマンスを決めるのは、更新処理の実装方法。参照処理は桁違いに速い 平均数10ms程度Datastoreパフォーマンスの監視ページhttp://code.google.com/status/appengine/
DatastoreサービスのAPIDatastoreサービスのAPIJDO (Java Data Objects)オブジェクトDBの標準API○:ドキュメントと実績が豊富×:性能が低い(LLAPIの1/3程度)、Bigtableと乖離しているJPA (Java Persistence API)ORMの標準API×:ドキュメントや実績が少ない
DatastoreサービスのAPIDatastoreサービスのAPIlow-level API(LLAPI)Bigtableにもっとも近い独自API○:性能が高い。Bigtableを理解しやすい×:低レベル。ドキュメントがあまりないSlim3 Datastoreひがやすを氏開発(サードパーティ)○:性能が高い。高レベルで使いやすい×:実績が少ない
DatastoreサービスのAPISlim3のパフォーマンステストツールの実行例
Datastoreのクエリ
クエリDatastoreのクエリとは複数のエンティティを条件検索できる通常、160~200ms程度で処理条件の記述方法JDOQLGQLQuery query = pm.newQuery("select from Employee " +                              "where lastName == lastNameParam " +                              "order by hireDate desc " +                              "parameters String lastNameParam")    List<Employee> results = (List<Employee>) query.execute("Smith");
Bigtableのスキャン
クエリ=インデックス+スキャンクエリは「インデックス+スキャン」で実装 Bigtableはクエリをサポートしていない「値」に基づく検索を実行できないすべてのクエリは、インデックスとスキャンの組み合わせで実現すべてのクエリの検索結果をあらかじめインデックステーブルに並べておく
3種類のインデックスDatastoreのインデックスとはエンティティテーブルとは別のテーブル3種類のインデックスカインドインデックス シングルプロパティインデックス コンポジットインデックス
カインドインデックスカインド名順でソートされたインデックス あるクラスのすべてのエンティティの一覧を提供 例:Empでカインドインデックスをスキャン SELECT * FROM Emp
カインドインデックス
シングルプロパティインデックス「エンティティの個々のプロパティ値」でソートされたインデックスすべてのプロパティについてデフォルトで作成インデックス不要なプロパティを明示できる昇順用と降順用の2つが作成される1つのプロパティを条件に検索/ソートできる例:name == ‘佐藤' 例:ORDER BY name 例:age >= 20 AND age <= 40
シングルプロパティインデックス
コンポジットインデックス「複数のプロパティ値の組み合わせ」でソートされたインデックス「カスタムインデックス」とも呼ぶ自動定義または手動定義複数のプロパティ値で検索できる例:dept_key = D1 & age >= 30 & age <= 40「Emp/D1/30」から「Emp/D1/40」までrangeスキャン「 < <= > >=」などの不等号条件(inequality filter)は、ひとつのプロパティに対してのみ利用可能
コンポジットインデックス
コンポジットインデックスコンポジットインデックスのデメリット すべてのプロパティ値の順列組み合わせでインデックス内容が作成されるので、インデックスサイズが膨大になりやすい クエリを多用/誤用するとインデックスが増え、更新処理が遅くなるmulti-value property利用時のインデックス爆発(index explosion)「ここぞ」という用途に限って使うべきできるだけコード上でのフィルタリングやソートがよい
マージジョインマージジョイン(merge join)とは 複数プロパティの等号条件(equality filter)検索をコンポジットインデックスに頼らずに実現例:dept_key = D1 & age = 40 & name = ‘佐藤’複数のシングルプロパティインデックスをマージしながら検索"zig-zag"アルゴリズムにより、個々のインデックスを並行してスキャン
マージジョインzig-zagアルゴリズムによるマージジョイン
Datastoreを構成するBigtableDatastoreサービスを構成する7つのBigtableEntitiesテーブルすべてのアプリのエンティティを保持EntitiesByKindテーブルEntitiesByPropertyASCテーブルEntitiesByPropertyDESCテーブルEntitiesByCompositePropertiesテーブルカスタムインデックステーブルID sequencesテーブル
EntitiesテーブルキーApp ID+パス(カインド名+IDまたはキー名)プロパティプロパティ名+プロパティ値のペアProtocol Buffer形式メタデータ	ルートエンティティのキー、カインド名カスタムインデックスデータインデックスID、祖先エンティティのキー一覧、プロパティ値一覧
インデックステーブルEntitiesByKindテーブルカインドインデックスを保持App ID、カインド名、エンティティキーEntitiesByPropertiy ASC/DESCテーブルシングルプロパティインデックスを保持App ID、カインド名、プロパティ名、プロパティ値、エンティティキーEntitiesByCompositePropertyテーブルコンポジットインデックスを保持インデックスID、App ID、カインド名、祖先エンティティのキー一覧、プロパティ値一覧、エンティティキー
その他のテーブルカスタムインデックステーブルコンポジットインデックスの定義を保持ID sequencesテーブルID採番用
クエリの制限テーブル間のjoinができない 非正規化して対処する 「正規化するな、JOIN済みのでっかいテーブルを作れ」 select * from PERSON p, ADDRESS awhere a.person_id = p.id and p.age > 25 and a.country = “US”↓select from com.example.Person where age > 25 and country = “US”複数のクエリに分割する multiple value propertyを使う
クエリの制限集約関数がない(group byできない) count()で全件カウントできない 毎回対象データをすべて取得してループで集計するのは非効率集約したい値は、集約用のエンティティを用意して集計 sharding counter: 書き込みが集中しないように複数のエンティティに分散して書き込みし、後で集計 memcache counter: memcacheに書き込みし、Task Queueでエンティティに保存
クエリの制限集約関数がない(group byできない) max()/min()で最大値/最小値を得られない 対象プロパティで降順/昇順でソートして、1件目の値を得る
クエリの制限関数やストアドプロシージャはない toUpper/toLowerなどがない 別のプロパティを設け、toUpper済みの値を入れる 書き込み時にできるだけ事前処理を行っておくことで、読み込みを高速化できる
クエリの制限クエリの構文の制約 全文検索ができない LIKEによる部分一致検索はできない 前方一致なら可能: name >= 'a' AND name <= 'a<UTF-8コードポイントの最大値>' 検索対象の文字列を形態素解析し、ワードごとのインデックスを作成する2010年に全文検索対応予定?
クエリの制限そのほかの制約 OR、!=が使えない近日対応予定inequality filters (< <= >= >)は1つのプロパティにのみ利用可能Text型やBlob型のプロパティはインデックスを作成できない(クエリできない)あるプロパティでinequality filtersを使うと、他のプロパティを最優先にしたソートができない
Backup Slides
Datastoreのトランザクション
エンティティグループとはエンティティグループとはエンティティ間の親子関係親(parent)と子(children)子のキーに親のキーを埋め込む最上位の親はルートエンティティ(root entity)と呼ばれる親は変更できないデフォルトでは個々のエンティティは個別のエンティティグループ(ルートエンティティ)となるDept1*Emp
エンティティグループとキー   /Grandparent:123    /Grandparent:123/Parent:52   /Grandparent:287    /Grandparent:287/Parent:85   /Grandparent:287/Parent:88/Child:47   /Grandparent:287/Parent:88/Child:66 カインド名ID親のキーパス
エンティティグループとはエンティティグループの指定方法明示的な指定子のキーを、親のエンティティのキーを使って生成する詳しい手順:http://d.hatena.ne.jp/uehaj/20090509/1241856856 JDOのowned関係UserとAddress間で親子関係を定義unowned関係はサポートしていない エンティティグループが個別になるのでACIDを保証できないため OOPやRDBの「関連(リレーション)」とは無関係関連をそのまま当てはめると問題も(後述)
エンティティグループとはエンティティグループの2つの役割ローカリティを指定するパフォーマンスの向上トランザクション・スコープを指定ACIDの保証CAP定理とエンティティグループ 特定範囲(ローカリティ)のみを対象にACID保証ACID001 abc002 def
ローカリティローカリティエンティティグループのすべてのエンティティは、1つのサーバーに保存される確率が高いより高いパフォーマンスが期待できる参考:http://groups.google.com/group/google-appengine-java/browse_thread/thread/fd758c65e14b5c76/e4afc1e348a36a36?show_docid=e4afc1e348a36a36大量のエンティティがある場合は複数サーバーに分割GFSによりデータは他2カ所にバックアップされるキー順でソートされている/Grandparent:Alice /Grandparent:Alice/Parent:Sam /Grandparent:Ethel /Grandparent:Ethel/Parent:Jane /Grandparent:Ethel/Parent:Jane/Child:Timmy /Grandparent:Ethel/Parent:Jane/Child:William /Grandparent:Frank
トランザクション・スコープDatastoreのトランザクション・スコープトランザクションの開始(begin)と終了(commit/rollback)を指示するエンティティ・グループエンティティグループ単位でACIDを保証 Bigtableは行単位のACIDしか保証しないDatastoreではエンティティグループ単位でのACIDを保証しているSERIALIZABLE相当異なるエンティティグループ間では保証されない
DatastoreとBASE楽観的排他制御(optimistic lock)を実装 エンティティグループのルートエンティティにて、トランザクションの最終コミット時間のタイムスタンプを記録 トランザクションの開始時に同タイムスタンプを確認コミット時にタイムスタンプを再度確認する タイムスタンプが変化していなければ、更新内容を保存して、タイムスタンプを更新タイムスタンプが変化してれば、他のトランザクションとの競合が発生しているので、トランザクションをロールバック
DatastoreとBASE楽観的排他制御(optimistic lock)を実装 RDBの悲観的排他制御(SELECT FOR UPDATE)のようにエンティティをロックしないスループットは高いが、競合時のリトライが必要Python版は3回まで自動リトライし、Java版は自動リトライしない
DatastoreとBASEリトライの例        for (int i = 0; i < NUM_RETRIES; i++) {            pm.currentTransaction().begin();            ClubMembers members = pm.getObjectById(ClubMembers.class, "k12345");            members.incrementCounterBy(1);            try {                pm.currentTransaction().commit();                break;            } catch (JDOCanRetryException ex) {                if (i == (NUM_RETRIES - 1)) {                     throw ex;                }            }        }
DatastoreとBASE分散トランザクションへの対応 App Engineでは異なるエンティティグループ間の分散トランザクション(グローバルトランザクション)はサポートされていないただしアプリレベルでの実装例はある http://code.google.com/intl/ja/events/io/sessions/DesignDistributedTransactionLayerAppEngine.html http://code.google.com/intl/ja/events/io/sessions/TransactionsAcrossDatacenters.html
トランザクションの注意点1 TX = 1 エンティティグループ1つのトランザクション内では、1つのエンティティグループの更新処理しか実行できない複数のエンティティグループを更新する場合は、個別のトランザクションが必要=ルートエンティティの更新は個別TXが必要1つのエンティティの更新は1回まで1つのトランザクション内では、1つのエンティティを複数回更新できない
トランザクションの注意点トランザクション内で実行可能なクエリの制限ancestor filterを持つクエリのみ実行可能コミット前の値は読み込みできないREAD_COMMITTED相当http://code.google.com/intl/ja/appengine/articles/transaction_isolation.html http://groups.google.com/group/google-appengine-java/browse_thread/thread/4a67044929428295
エンティティグループのボトルネック1つのエンティティグループにトランザクション負荷を集中させないエンティティグループの利用は必要最小限に抑えた方が性能は向上する リレーショナルモデルやオブジェクト指向の関連をそのままあてはめると問題が生じることも Dept1*Emp
エンティティグループのボトルネック例:1つのDepartmentと1000のEmployee1000のEmployeeのうち、いずれか1つのEmployeeしか同時にトランザクションを実行できない他はエラーとなりリトライが必要例:1つのUserと数個のAddress1人のユーザーの住所に対して複数のトランザクションが同時実行される頻度は低い負荷は集中しない

CBA Google App Engine 20101208