前回ちょろっと書きましたが、backends で DatastoreTimeoutException が発生して結構ハマりました。
コチラのまとめをブログに書いておきます。
Backends での Query で DatastoreTimeoutException – Google グループ
環境
Slim3 1.0.15
appengine java sdk 1.7.0
HRD
BackendsのインスタンスはB8です。
概要
Backends で Query で100万件位を Key で取得しようとすると、 DatastoreTimeoutException が発生しました。
kind は ほぼ Key のみで、Avarage Sizeは200Byte位で、Entityはトータルで数百万件あります。
TaskQueue で処理するには量が多すぎるので Backends ならなんとかなるかなと思ったのですが、ログを見る限りQuery が60秒位でタイムアウトする様に見えます。
カーソル+イテレーション
Pythonだと、イテレータを使ってループしていると、裏で適当な件数ずつ取得しながらイテレーションしてくれるとい情報を元に、試してみました。
java のLow Level APIのカーソルのんにも asQueryResultIterator()メソッドがあるようですし、slim3 にもありました。
こんな感じでやってみました。
MyModelMeta m = MyModelMeta.get(); S3QueryResultIterator<mymodel> i = Datastore.query(m) .filter(m.key.greaterThan(fromKey)) .filter(m.key.lessThanOrEqual(toKey)) .encodedStartCursor(encodedCursor) .asQueryResultIterator(); while (i.hasNext()) { MyModel entity = i.next(); // do something.... } </mymodel>
やはりクエリ開始から1分位で、 DatastoreTimeoutException が発生してしまいました。
prefetchSize と chunkSize を明示指定(1, 5000, 10000, 50000を試した)しても変わらずでした。
カーソル
こんな感じで、イテレーションを使わずにカーソルでのクエリをぐるぐる回す事で、100万件位ならいける事を確認しました。
ただし、時折「Process terminated because the backend took too long to shutdown.」とか言われて処理が途中で止まります。
S3QueryResultList<myclass> s3QRList = Datastore.query(meta) .filter(meta.key.greaterThanOrEqual(fromKey)) .filter(meta.key.lessThan(toKey)) .prefetchSize(50000) .chunkSize(50000) .limit(50000) .asQueryResultList(); for (MyClass entity : s3QRList) { // do something } while (s3QRList.hasNext()) { String encodedCursor = s3QRList.getEncodedCursor(); s3QRList = Datastore.query(meta) .filter(meta.key.greaterThanOrEqual(fromKey)) .filter(meta.key.lessThan(toKey)) .encodedStartCursor(encodedCursor) .prefetchSize(50000) .chunkSize(50000) .limit(50000) .asQueryResultList(); for (MyClass entity : s3QRList) { // do something } } </myclass>
まとめ
今回判った事は、 (java sdk 1.7.0現在)
1) backends で Datastore の操作が長すぎる(60秒?)と DatastoreTimeoutException が発生する
2) java版では、イテレーションでよしなにやってくれる訳ではないかも(Low Level API は試してないので断言は出来ないです)
3) カーソル等でDatastoreの操作を細分化する事で DatastoreTimeoutException は回避できる
4) 時折「Process terminated because the backend took too long to shutdown.」とか言われて処理が途中で止まる事がある
といった所です。