GAEのトランザクションについて個人的なまとめ
今、GAEで何か作ろうとしているわけではないけど、分散トランザクションの勉強になりそうなので、自分の言葉でまとめてみる。
エンティティグループとは。
エンティティグループは、親子関係にあるエンティティのあつまりのこと。
ヘッダ・明細とか。
http://d.hatena.ne.jp/higayasuo/20091110/1257854009
http://code.google.com/intl/ja/appengine/docs/java/datastore/relationships.html#Relationships_Entity_Groups_and_Transactions
GAEのトランザクション
エンティティ単位で、楽観的排他なトランザクション。
エンティティは、RDBで言うとレコードと思えばいい。
複数のエンティティの更新を、1つのトランザクションで実行できない。
例えば、よくあるのは銀行の送金モデル。
でも、同じエンティティグループのエンティティは、1つのトランザクションで更新できる。
送金モデルの場合は、送金元、送金先の口座のエンティティが同じエンティティグループ
に属していれば、アトミックに更新できる。
これは、GAE内でどう実現されているかというと、rootエンティティにタイムスタンプが
あって、トランザクション開始時のタイムスタンプを覚えておいて、子エンティティの更新などをした後、commit するときに、rootエンティティのタイムスタンプが変わってないことを確認することで、実現しているらしい。
(下の方 http://d.hatena.ne.jp/higayasuo/20091111/1257905482 )
ただし、エンティティグループを使う方法だと、銀行にある全ての口座を1つのエンティティグループに含めないといけなくなる。
でも、ロックはエンティティグループ全体にかかるので、ある口座の更新処理が、まったく関係のない口座の更新をロックしてしまうことになってしまうので、大きな問題。
じゃ、更新するときだけ、エンティティグループを作ればいいんじゃないかと。
例えば、送金処理をするときに、送金元と送金先の口座を子として持つ、親エンティティ(例えば、送金イベントみたな)を作ればいいんじゃないかと。
と思ったんだけど、それはできない。
一度作成したエンティティに新たに親を設定することはできない。
http://hyperlab2.blogspot.com/2009/12/blog-post_17.html
http://code.google.com/intl/ja/appengine/docs/java/datastore/relationships.html#Relationships_Entity_Groups_and_Transactions
ジャーナルを使用した多層コミット
上記の制限を超えるために、ジャーナルを使用した方法が出てきた。
詳細は、ここの説明がわかりやすい。
http://songofcloud.gluegent.com/2010/01/blog-post.html
簡単に言うと、以下のような感じ。
更新対象のエンティティを直接更新せず、ジャーナルというエンティティに更新内容を一旦保存し、あとからその内容を適用する。
そして、ジャーナルがちゃんと適用されたかどうかを管理するために、ジャーナルの適用状態を管理するためのエンティティを導入する。
以下も参照。
http://blog.notdot.net/2009/9/Distributed-Transactions-on-App-Engine
http://songofcloud.gluegent.com/2009/11/blog-post_18.html
http://songofcloud.gluegent.com/2009/11/blog-post_24.html
http://d.hatena.ne.jp/higayasuo/20100210/1265781747
songofcloud で書いてあったことだけど、エンティティをまたいだ更新をするときは、以下の考え方が重要。
- クリティカルな部分(実際のデータの更新)は、トランザクションを使う。
- エンティティグループをまたいだ処理は、べき等性のある処理で。
べき等性とは、
- 1回成功すると、2回目以降は作用を起こさない。
- 何度失敗しても副作用を起こさない。
ちなみに、Slim3は、デフォで用意してくれている。
バージョン管理による楽観的排他制御
GAEが提供するトランザクションとは別に、バージョン番号による排他も必要。
http://d.hatena.ne.jp/higayasuo/20091120/1258731010
例えば、WEBで、あるデータの編集画面を表示している間に、誰かが裏で先にそのデータを更新してしまったときに、そのあとの更新を防ぐやつ。
ちなみに、Slim3は、デフォで用意してくれている。
まとめ
GAEにおいては、Slim3 を使えば万事OK。