Skip to content
vvakame edited this page Dec 7, 2012 · 6 revisions

Memvache について

主旨としては、Datastoreに対する操作するとお金がえらいかかるのでMemcacheに可能な限り仕事させたいというお話。

動作内容

Datastore への 単一 Entity の Get & Put の置き換え

code

現状、普通にプログラム書くとすると、プログラマが以下のような処理を記述する場合がほとんど。

  1. Datastoreにデータを読出 and 保存を行いたい。
  2. Memcacheからデータを読む。
  3. Memcacheからデータが取れなかった場合、Datastoreからデータを取ってくる。
  4. データを更新する。
  5. Datastoreに保存する。
  6. Memcacheに保存する。

これに、Delegateを噛ませてDatastoreのPut&Get時にMemcacheへの操作を同期的に行い、結果を差し替える。 全てのPutに対して適切に処理をすると、古いEntityを返してしまう心配はない。 Tx有りのGetの場合はMemcache無しで素通ししなければならない。

MemcacheのKey = EntityのKey

Datastore への Query をKeysOnlyに差し替え (積極的キャッシュ)

code

Entityごとガッツリ持ってくるQueryについて、KeysOnlyに書き換えてQueryを実行。 取得できたKey群について、個別にMemcacheからEntityを取得する。取得できなかった分はまとめてBatchGetする。

MemcacheのKey = EntityのKey

Datastore への Query をまるごとキャッシュする (超積極的キャッシュ)

code

全ての種類のQueryについて、レスポンスをまるごとMemcacheに保存し活用する。 EntityがPutされた場合にQueryのキャッシュを破棄しなければならない。しかし、Memcacheから器用に特定のKindに関連したQueryのキャッシュを消すのは難しい。そのため、Kind単位にカウンタを持ち、MemcacheのKeyの生成にそのカウンタを利用する。もし、該当のKindのEntityがPutされた場合、カウンタの値をインクリメントする。結果、そのKindのQueryのキャッシュは参照できなくなり、上手く動くようになる。

MemcacheのKey = Namespace + @ + Kind + @ + クエリのハッシュ値 + カウンタの値

もし、Foo Kindのカウンタが3で、Namespace=FizzのQueryを投げると Fizz@Foo@123abc@3 のような値になる。 もし、Foo Kindに対してPutがあった場合、カウンタは4になりMemcacheのKeyが Fizz@Foo@123abc@4 のようになる。 これにより、古いキャッシュは参照されないようにすることができる。

問題点として、QueryがEventualなため最新ではないQueryResultをキャッシュしてしまった時に困る(Entityは最新しか取れない)。