前回ちょろっと書きましたが、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.」とか言われて処理が途中で止まる事がある

といった所です。