LoginSignup
4
3

More than 5 years have passed since last update.

GAE SE/pyのdatastore NDBが保存するmemcacheの場所

Posted at

Google AppEngine Standard Environmentのpythonにはdatastoreのマッパーであるndbがとても便利で使いやすいです。

このライブラリは内部でキャッシングを行なってくれるため、平均取得時間の遅延を下げてくれます。
内部ではIn-Contextキャッシュとmemcacheを使ったキャッシュを併用しています。

NDB Caching

datastore更新後もmemcacheにキャッシュが残る

memcacheを使わないコンテキストでの更新やGCEや外部からの更新時に、memcacheの更新を怠ってしまうとキャッシュの削除が行われずに、いつまでも更新後のデータが取得できなくなるケースがあります。

AppEngineからキャッシュをdisableにして保存

AppEngineから保存する時に、contextのポリシーでmemcacheへの同期をoffにして保存等してしまうと、キャッシュを利用している別のcontextと不整合が起きてしまいます。

appengine_view.py
from google.appengine.ext import ndb

class Item(ndb.Model):
  name = ndb.StringProperty()

item = Item.get_by_id('item1')
item.name = 'car'
item.put()  # 通常はmemcacheにも保存されます

# キャッシュを使いたくないケースで、memcacheをcontext内でオフにしてしまう 
ctx = ndb.get_context()
ctx.set_memcache_policy(False)

item = Item.get_by_id('item1')
item.name = 'train'
item.put()  # キャッシュポリシーがOFFだとmemcacheに保存されません

実際に、memcacheをオフにするケースはtaskqueue等で非同期で更新していたりするケースが多いと思いますが、時々遭遇してしまいます。

memcacheにアクセスできない環境から保存

GCEや外部など、memcacheにアクセスできない環境からdatastoreの更新や保存をした場合に、memcacheに保存されずに不整合が起きます。
google-cloud-pythonライブラリなどを使うことが多いと思いますが、その時に遭遇することが多いです。

gce.py
# google-cloud-pythonを使った場合
from google.cloud import datastore

client = datastore.Client('my-project')
item = client.get(client.key('Item', 'item1'))
item['name'] = 'airplane'
client.put(item)  # memcacheには保存されません。

(GCE上などからmemcacheの読み書きをする方法を知らないので、知っていたら教えてください。)

コンソール上で編集

コンソール上で編集する機能がありますが、これで編集してしまってもmemcacheには保存されない現象が起きてしまいます。
静的なconfig等をdatastoreで管理していて、それを更新した時に反映されない、といったケースに遭遇しました。

解決策

memcache全体をクリア(flash)すれば解決

memcache上に保存されているものを全て削除してしまえば、このような問題は解決します。
Memcacheのページからもフラッシュできます。

しかし、appengineからのdatastoreアクセスのパフォーマンスがその時に低下してしまうと思われるので、あまりやりたくないケースも多いですよね。

memcacheの該当データだけ削除

該当のデータだけmemcache上から削除すれば、そのデータだけが再取得されるので、全体のパフォーマンスへの影響を減らせるかと思います。

保存しているkeyを知って入れば良いのですが、ndb内部でmemcacheへ保存するときのkeyを決めています。
具体的にはprefix + entityのkeyのハッシュです。
prefixはndb.Context._memcache_prefixに定義されていますが、appengine sdk 1.9.55ではNDB9:となっていました。

なので以下のようにすれば削除できそうです。

item = Item.get_by_id('item1')

memcache.delete('{}{}'.format(ndb.Context._memcache_prefix, item.key.urlsafe()))

ndbライブラリ自体はappengineのpython sdkに含まれていて、github等で公開されていない?のでソースを見てみる必要があって少しわかりづらかったです。

中身もアップデートはあまりされていないみたいですし、先行きは少し不安ですね。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3