Scaleするかどうか、それが問題だで主張したとおり、クラウドではスケールしなければ意味がない。以下は、GAEで大規模な処理をやって、特にトランザクション処理で悪戦苦闘した際のメモである。本日の発表資料=>ココにも含まれている。
大量データをINSERTできない件について
先日、Entityとトランザクション2において、Ownedな関連を使ったUpdateサンプルを紹介したわけだが、実はこれ、大量データをINSERTすると急激に遅くなるという問題を含んでいることがわかった。実際にテストしてみたところ、15000件を超えた時点でタイムアウトが頻発、15300件からはとうとう1件も登録できなくなってしまった。
com.google.apphosting.runtime.HardDeadlineExceededError: This request (c1fe232d20adabba) started at 2009/08/11 07:12:31.975 UTC and was still executing at 2009/08/11 07:13:05.802 UTC.
原因としては、1)インデックス作成における負荷、2)所有関係を作成する負荷、が考えられるが、3)JDOのトランザクション処理自体に問題がある可能性もあるので、その場合はLow Level APIの利用も視野に入れなければならないと考えた。
トランザクション処理の必要性
トランザクション処理でここまで嵌ってしまうと、ACIDじゃなくて別のよい方法はないものかという考えに傾いていく。最近よくBASEという考え方が紹介されていて、ACIDが大変なんで、BASEでいいんじゃないかと思うこともある。あるいは、エラー忘却型コンピューティングとか、BASEの1種になるかもしれないが、Saga(ロングトランザクション)モデルといった補正トランザクションなどを利用しようという考え方もある。Sagaは、Webサービスが密に結合しているようなシステムにおいて過去多く見られた。最近のRESTfulなシステムへの導入では、ステートレスになじまないことでやや否定的だが、やろうと思えば可能だろう。(参考:RESTとトランザクション?)
しかし、ロングトランザクションなどのACIDではない仕組みに関しては、補正失敗のケースも考慮しておかないと運用面で支障をきたすことになるので要注意である。
私は以前作ったWebサービス連携のエラーリカバリーで酷い目にあった経験があるので、この手のものをACIDで組まないことに、ものすごく悲観的である。ACIDによる一貫性保証がないカウンタの実装などは特に嵌る。そして、すぐに不具合を見つけることができないことが問題を大きくする。単体テストでは成功して、本番運用に入っても数日は成功するので一見うまくいくように思うかもしれないが、失敗の失敗、つまり、リカバリーの失敗までを考慮していないと、破綻は必ず訪れることになる。(マーフィーの法則「起きる可能性のあるものは必ず起きる」)(関連:信頼性とジレンマ)
調査結果および対応策
話は戻り、パフォーマンス劣化の原因について調べてみた。そして、なんとかACIDでやる方法はないものか、もう一度考えることにした。
一度に100件登録した場合
<所有関係の負荷>
* 所有関係あり: 15秒くらいから。件数が増えるとだんだん遅くなる。
* 非所有: 3秒くらい。件数が増えても変わらない。
<Index作成の負荷>
* インデックスなしと、インデックスありの、どちらも100件登録で3秒くらい。
* インデックスありのテーブルで、100000件弱登録できた。
* 登録にかかる時間も100件約3秒と変わりなし。
以上の結果のとおり、Indexの数というより、所有関係の方がパフォーマンスへの影響が大きいということがわかった。所有関係については、それを解消しなければ、ほとんど使い物にならないような感じであった。
所有関係とEntityGroupについて
実はEntityGroupと関連に直接的な関係はない。そもそも親子関係をしているのは、JDOのowned関係がEntityGroupとみなされることを利用してトランザクションを実行したいからであった。しかし、そうしなくても、明示的なKeyの生成、つまり、子のキーを親のエンティティのキーを使って生成することでEntityGroupは作成できるのだ。パフォーマンスを出すには、Owendな関連を解除して、Keyの親子関係で関連付けたEntityGroupを使って、トランザクションを実行すればよいことがわかった。
以上の結果を踏まえてコードを修正した。
3 件のコメント:
kazunori_279と申します。教えていただきたいのですが、
- 1つの親子関係において、子を10000件挿入したケースと理解してよいでしょうか?
- ownedではなくentity groupのみにした場合のパフォーマンスはどうなりましたでしょうか?
どうも、いつもお世話になっております。
1.親子関係は、1つの親(カウンタとListの子をもつ)に対して、10000件挿入したケースです。
2.entity groupのみにした場合のパフォーマンスは件数が増えても安定して3秒以内で返ってきます。数十万件以上でも容量限界までいけそうな感じです。
なるほど、安心しました。私がいま作っているシステムでも子が数1000に及ぶケースがあるので、性能低下があるとどうしようと思ってましたが、owned関係ではないので大丈夫そうです。貴重な情報どうもでした!
コメントを投稿