スティルハウスの書庫の書庫

はてなダイアリーで書いてた「スティルハウスの書庫」を移転してきました。

DatastoreTimeoutExceptionって何?

Datastoreで大量のエンティティを扱うようなコードを走らせると、DatastoreTimeoutExceptionがしょっちゅう出ます。こんな感じ:

Caused by: com.google.appengine.api.datastore.DatastoreTimeoutException: Unknown
	at com.google.appengine.api.datastore.DatastoreApiHelper.translateError(DatastoreApiHelper.java:38)
	at com.google.appengine.api.datastore.DatastoreApiHelper.makeSyncCall(DatastoreApiHelper.java:56)
	at com.google.appengine.api.datastore.DatastoreServiceImpl$PreparedQueryImpl.runQuery(DatastoreServiceImpl.java:342)
	at

MLで検索してみると、Jason(Google)さんのお返事が:
http://groups.google.com/group/google-appengine-java/browse_thread/thread/31e1f21cf5deff07/ced822ff4537b34d?lnk=gst&q=DatastoreTimeoutException#ced822ff4537b34d

The majority of exceptions are thrown because two or more requests come in
at the same time that attempt to write to a single entity or entity group.
This results in write contention, and an exception may be thrown if a given
request can't complete its write within the deadline. So, during your design
stage, be sure to identify areas where this may be a problem and mitigate as
much as possible. You can do this by keeping your entity groups small and
sharding single entities that may updated a lot, such as a global counter:

http://code.google.com/appengine/articles/sharding_counters.html
  • 1つのエンティティやエンティティグループに書き込みが集中すると、時間内に書き込みが終わらず例外が出ることが多い
  • よって、設計時点で負荷の集中を避けるようにすべし。エンティティグループを小さくし、グローバルカウンターのような更新の集中するエンティティは分割する

それはわかりますが。。でも書き込みのない単純なクエリでも例外が起きるんですよね。

Due to the distributed nature of App Engine's datastore, these exceptions
will happen from time to time; in practice, this effects between 0.1 and 0.2
percent of all datastore operations, and we are always working to make this
percentage even lower. For critical datastore operations, you should
continue to catch the exception so you can provide a custom error if
necessary or perform your own retries.

To reduce the number of times you catch the exception, you could write a
function to persist an entity, and then only include the try-catch block in
that function. 
  • Datastoreは分散システムなので、全アクセスの0.1〜0.2%くらいは例外が出る(1000回に1回か〜多いな!)
  • 重要な処理については例外をキャッチしてエラー処理したりリトライするよう書くべき
  • 例外をキャッチする回数を減らすには、個々のエンティティの書き込みごとにtry/catchを書くべし

…ふ〜む。

今私の環境で出ているDatastoreTimeoutExceptionには2種類あって、

  • 数1000件単位で読み書きしてると、ぽつぽつ出る
  • 特定のクエリを実行しようとすると必ず出る

前者は上記の説明で納得ですが、後者はおそらく対象のエンティティの1つが壊れてしまっているのかな。。?などと想像してます。さてどうしたものか。

追記

30分くらいいじっていたら、いつのまにか例外が出なくなりました。。なんでだろう。自分のあずかり知らないところで調子悪かったり直ったりするところがクラウドプログラミング。