トランザクションとエンティティグループ
Datastoreのトランザクション
- エンティティグループ単位でACIDを保証
- Bigtableは行単位のACIDしか保証しない。Datastoreではエンティティグループ単位でのACIDを保証している
- 楽観的排他制御(optimistic lock)を実装
- クエリはトランザクショナルではない
- トランザクションには含まれないので、読み取り一貫性(repeatable read)は確保されない
- ただしコミット前の値の読み込み(ダーティリード)は発生せず、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つのトランザクションに含めたいエンティティの集まりを示す
- リレーショナルモデルやオブジェクト指向の関連(リレーション)ではない
- エンティティグループに含まれるすべてのエンティティは、1つのサーバーに保存される
- Datastoreでは、通常のDBと同様に、トランザクションの開始(begin)と終了(commit/rollback)を指示する
- 同じエンティティグループに属するエンティティについては、ACID特性が保証される
- 異なるエンティティグループ間では、ACID特性が保証されない
- エンティティグループを明示的に指定しない場合、個々のエンティティは個別のエンティティグループを形成する
- エンティティグループは、JDOのowned関係を指定することで、自動的に形成される
- 例えば、UserとAddress間で親子関係を定義すると、AddressはUserのエンティティグループに属する
- owned関係にない場合も、明示的に指定できる
- 子のキーを、親のエンティティのキーを使って生成することで、エンティティグループが形成される
- 詳しい手順:http://d.hatena.ne.jp/uehaj/20090509/1241856856
- unowned関係はサポートしていない
- エンティティグループが個別になるのでACIDを保証できないため
エンティティグループ設計時の注意点
- 1つのエンティティグループにトランザクション負荷が集中しないように注意する
- エンティティグループの利用は必要最小限に抑えた方が性能は向上する
- リレーショナルモデルやオブジェクト指向の関連をそのままあてはめると問題が生じることもある
- 連番の採番はどうする?
- 例:大量に書き込まれるメッセージの1つ1つに、書き込み順の連番を振りたい
- 単純な方法:採番用エンティティのMessageIndexをルートエンティティとし、Messageを子とする
- MessageIndexとMessageが同じトランザクションで更新処理され、ACIDを確保できる
- しかし大量のメッセージ書き込みには対応できない
- 対処方法:採番用エンティティを分散化する
- ユーザーごとの採番用エンティティUserIndexをルートエンティティとし、Messageを子とする
- MessageのIDには「タイムスタンプ+ユーザーID+UserIndexで採番した値」を設定する
- UserIndex単位のトランザクションとなり、大量の書き込みが可能となる
- タイムスタンプ順でソート可能で、かつユニークなIDとなる
- 別の対処方法:GUIDベースとする
- 「タイムスタンプ+長い乱数」など
- 参照:Google I/O 2008 - Building Scalable Web Apps with App Engine