appengine ja night #5に いってきました
Kayの人
@tmatsuo
正規化しすぎるとだめ
class Tag(db.Model) name = db.StringProperty() count = db.IntegerProperty() class Post(db.Model) tags = db.ListProperty(db.Key) body = db.TextProperty()
JOINが使えないので検索はこんな感じ...
t =Tag.get_by_key_name(tag_input) if t is None: raise Http404 posts = Post.all().filter("tags = ",t.key()).fetch(200)
上記の場合はPostモデルにStringListを持った方が、無難
- 質問
- Q:タグ名を変更する場合は全Postをなめて変更するのか?、
- A:TaskQueueかRemoteAPIで全部を変更するか,Modelにバージョンを持つ
- 最近1.3.1でクエリが早くなった->複数クエリを発行することに躊躇する必要はなくなった?
- GETとQueryは変わらない
- KeyでGETは18msec程度
- KeyでQueryは23msec程度(ヒットが1つの場合)
- 場合場合によってモデル設計を考える
不要なIndexを付けないように
db.StringPropertyはデフォルトでIndexが付いてしまう
class Foo(db.Model) prop1 = db.StringProperty() prop2 = db.StringProperty() prop3 = db.StringProperty() prop4 = db.StringProperty()
インデックスを付けない
class Foo(db.Model) prop1 = db.StringProperty(indexed=false) prop2 = db.StringProperty(indexed=false) prop3 = db.StringProperty(indexed=false) prop4 = db.StringProperty(indexed=false)
インデックス名を短くする
class Foo(db.Model) prop1 = db.StringProperty(name="p1") prop2 = db.StringProperty(name="p2") prop3 = db.StringProperty(name="p3") prop4 = db.StringProperty(name="p4")
GQLを書いた場合kindが必要だが
kind名を短くする
@classmethod def kind(cls) return "z"
参考
http://code.google.com/intl/ja/appengine/docs/python/datastore/gqlreference.html
- 無料で保存できるデータ容量は限られているのでこれらをできるだけ短い名前にする
- app engineの管理ツールでDBのうちどれくらいがメタデータかを見ることができる
- モデルにIndexが何個あるかによってもパフォーマンスが変わる 1個Indexが追加される毎に16msec(cpu time)
- 検索に使わないのであればIndexを無駄に張らない
db.StringProperty(indexed=false)
から
db.StringProperty(indexed=true)
に変更したばあいfalse時代のものは検索に反映されない!!
http://code.google.com/intl/ja/appengine/docs/python/datastore/queriesandindexes.html
Exploding Index
q = MyModel.all().filter("contents ="."word1").¥ filter("contents ="."word2").¥ filter("contents ="."word3").¥ order("-created") entries = q.fetch(10)
このクエリにたいしてcontents,contents,contents,createdというインデックスを作ろうとする
content数xcontent数xcontent数xcreated数 の膨大なIndexを作ってしまう(Max 5,000件)
q = MyModel.all().filter("contents ="."word1").¥ filter("contents ="."word2").¥ filter("contents ="."word3").¥ finter("created_month=".this_month) entries = q.fetch(1000) entries.sort(cmp=lmbda x,y: cmp(x.created,y.created)
on memoryでsortするように心がける
Composite Indexを作ると危険!!
- アイデア
- Keyに時刻を埋め込むとorderが不要になる
- marge joinの仕様でsortされることがおそらく保証されている
- Keyに時刻を埋め込むとorderが不要になる
- 質問
- Q.1000件を越えるInmemory sortは?
- A.ヒープ領域(100M程度)が許す限りin memoryで可能
Greedy module loading
- 一部でしか使用しないモジュールは遅延ロードするべき
- スピンアップはなるべく短く
# -*- coding: utf-8 -*- from kay.utils import render_to_response import hoge_utils import fuga_utils import moge_utils def index(request) return render_to_response('myapp/index.html',{'message':'hello'}) def hoge(request) hoge_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'}) def fuga(request) fuga_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'}) def moge(request) moge_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'})
先頭でimportしている
apache+mod_pythonの場合はこの方が効率が良い
GAEでは以下の用に 遅延ロードしたほうがよい
許されるスピンアップは10秒程度
# -*- coding: utf-8 -*- from kay.utils import render_to_response def index(request) return render_to_response('myapp/index.html',{'message':'hello'}) def hoge(request) import hoge_utils hoge_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'}) def fuga(request) import fuga_utils fuga_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'}) def moge(request) import moge_utils moge_utils.get_entries() return render_to_response('myapp/index.html',{'message':'hello'})
参考
1.3.1の新機能紹介
Transactional Task Queue
http://pixiv.cc/mix3/archives/51343747.html
DBのTransacion内にTaskQueueを積む動作を入れておく
commitが成功した場合にのみ積まれる
不整合が起きにくい
- 質問
- Q.TaskQueueは一時間後とか指定できる
- A.できる etaかcount downで指定可能 正確とは限らないけど。
- Q.TaskQueueのQueueのサイズに上限がある?
- A.なし、ただしスピードは同時に秒間20タスクが上限
Cursor
Pagingに使えそう
任意ページに飛んだり、戻るにはもう一捻り
Appstats(Python版のみ)
http://blog.shehas.net/2009/12/11/Kay-appstats
- 以下のYSlow的なものが見える
- RPCの統計
- URLアクセス統計
- Requestの履歴
app.yaml
- url: /sats_*
ひがやすをさん
複数のエンティティグループに跨ったTransaction(グローバルトランザクション)
エンティティグループはできるだけ小さく作る
2phase commit
複数のDBに跨るようなTransactionのプロトコル
分散トランザクションに挑戦しよう!
- リソースマネージャ
- トランザクションコーディネータ
- 一般的なトランザクション
- ジャーナルに書きだし
- 内部コミット
- ジャーナルの適応