本エントリは、エントリ「JJUG CCCいってきました」の一つです。セッションのメモ書きです。もとの発表資料: A-3-1.pdf, A-3-2.pdf
スケールするために
- 無駄な繰り返しを避ける
- 繰り返されるクエリ結果はmemcacheでキャッシュする(読み込みデータのための)
- 大きなリザルトセットは避ける
- メモリ上で大量のデータのソートやフィルタはしない。小さくとって、小さく処理。
チューニングのために知っておく方がいい数字
- 書き込みはコスト高い。ほんとの最低でも1ms。データ量に応じさらに悪化。
- 読み込みは速い。25micro second。1秒に4GBのスループット。
EntityとKind
- 実体は「分散ソートアレイ」と呼ばれるもの。多数のマシン上で実行。
- EntityはKeyとvalueをもつ。
- valueは、プロパティのキー+バリューをずらりとシリアライズして突っ込んでいるだけ(たぶん)。検索はindex経由で(indexが張れるのはblob, text以外のデータ型)。
- keyは(1)Kindのクラス名+ID、(2)文字列型のいずれか。後から変更不可。500バイト制限がある。
- 関連はRelationプロパティで表現
- OneToMany, ManyToMany可
- 癖がある。単純なリレーションではない。
EntityGroup
- 親子関係
- 書き込みに関してEntity Group単位で排他制御される。
- 書き込み排他の実現方法はロック(+解除されるまで待つ)ではなく楽観ロック+自動リトライで実現(root Entiyに最終更新時刻を記録し、書き込み前に取得した値から変化していれば自動リトライ)。コード上は意識しなくていいが、競合が頻発すると遅くなるorタイムアウトを引き起こす。
EntityGroupの落とし穴
- 大きく作ると遅くなる(EntityGroupに含まれるデータ量が多いと同時アクセスが生じる確率が高まり遅延の確率が高まる)
- データの利用パターンに合わせて小さくする。
- Entity Groupをまたがったクエリはロックされない。 (疑問:Entity Groupをまたがるということはクエリ対象が別マシンにまたがる可能性もある?分散クエリになって遅くなる可能性もある?)
カウンタを作ってみよう
- Memcacheは駄目。1000件しかクエリできない。
- Entityを使う。しかし頻繁にupdateされると遅い。
- →「分散カウンタ」。同じEntityGroupに所属しないn個のカウンタを作って、インクリメントする際にはランダムにn個のうち1個を選んで増加。カウント値を得るときにクエリして合計する。
ブログを作ってみよう
- エントリに関して
- ページネーションは難しい。EntityのKeyのIDは重複はないが番号が飛ぶ(稠密ではない)のでページングには不適切。
- エントリをブログ全体の子供にして、ブログに番号を持たせる。
- → 記事の投稿は頻繁ではないのでOK。
- コメントに関して
- エントリと同じ方式だと、炎上したときなどに大量コメントの登録更新が遅延して困る。
- 「時刻+ユーザ名+コメントID」をキーとしてソートする。コメントIDのカウンタをユーザの子にしてGroup化する。
- → 同じユーザが頻繁には投稿できないのでOK。