我一直致力于创建一个自动缓存的db.Model子类,即:
我开发了以下方法(这似乎对我有用),但我有几个问题:
以下是我目前的实施情况。我非常感谢有关缓存实体的任何和所有指导/建议(即使您的回复不是上述4个问题之一的直接答案,但与整个主题相关)。
from google.appengine.ext import db
from google.appengine.api import memcache
import os
import logging
class CachedModel(db.Model):
'''Subclass of db.Model that automatically caches entities for put and
attempts to load from cache for get_by_key_name
'''
@classmethod
def get_by_key_name(cls, key_names, parent=None, **kwargs):
cache = memcache.Client()
# Ensure that every new deployment of the application results in a cache miss
# by including the application version ID in the namespace of the cache entry
namespace = os.environ['CURRENT_VERSION_ID'] + '_' + cls.__name__
if not isinstance(key_names, list):
key_names = [key_names]
entities = cache.get_multi(key_names, namespace=namespace)
if entities:
logging.info('%s (namespace=%s) retrieved from memcache' % (str(entities.keys()), namespace))
missing_key_names = list(set(key_names) - set(entities.keys()))
# For keys missed in memcahce, attempt to retrieve entities from datastore
if missing_key_names:
missing_entities = super(CachedModel, cls).get_by_key_name(missing_key_names, parent, **kwargs)
missing_mapping = zip(missing_key_names, missing_entities)
# Determine entities that exist in datastore and store them to memcache
entities_to_cache = dict()
for key_name, entity in missing_mapping:
if entity:
entities_to_cache[key_name] = entity
if entities_to_cache:
logging.info('%s (namespace=%s) cached by get_by_key_name' % (str(entities_to_cache.keys()), namespace))
cache.set_multi(entities_to_cache, namespace=namespace)
non_existent = set(missing_key_names) - set(entities_to_cache.keys())
if non_existent:
logging.info('%s (namespace=%s) missing from cache and datastore' % (str(non_existent), namespace))
# Combine entities retrieved from cache and entities retrieved from datastore
entities.update(missing_mapping)
if len(key_names) == 1:
return entities[key_names[0]]
else:
return [entities[key_name] for key_name in key_names]
def put(self, **kwargs):
cache = memcache.Client()
namespace = os.environ['CURRENT_VERSION_ID'] + '_' + self.__class__.__name__
cache.set(self.key().name(), self, namespace=namespace)
logging.info('%s (namespace=%s) cached by put' % (self.key().name(), namespace))
return super(CachedModel, self).put(**kwargs)
答案 0 :(得分:2)
为什么不切换到已经实现模型实例内存缓存的NDB,而不是重新发明轮子?
答案 1 :(得分:1)
您可以查看Nick Johnson关于添加pre and post hooks for data model classes的文章,作为覆盖get_by_key_name的替代方法。这样,即使使用db.get和db.put也可以使用钩子。
也就是说,我在我的应用程序中发现,我在更高级别上有更多戏剧性的性能改进缓存 - 就像我需要渲染整个页面的所有内容,或者如果可能的话,页面的html本身。 / p>
您还可以查看asynctools库,它可以帮助您并行运行数据存储查询和缓存结果。
答案 2 :(得分:0)
我想要实施的Nick Johnson的很多好的提示已经在模块appengine-mp中实现了。比如通过protocolbuf或预取实体进行序列化。
关于您的方法get_by_key_names
,您可以check the code。如果您想创建自己的db.Model层,也许这可以帮助您,但您也可以为改进现有模型做出贡献。 ;)