覆盖get_by_key_name()以使用memcache

时间:2012-01-20 17:00:16

标签: python google-app-engine google-cloud-datastore

使用另一个使用memcache保存数据库查询的函数覆盖get_by_key_name是否有意义?如下?在这个例子中,memcache密钥只包含实体key_name,只是为了简单...

class Entity(db.Model):
   @classmethod
   def get_by_key_name(cls, key_name):
     entity = memcache.get(key_name)
     if entity is not None:
       return entity
     else:
       entity = cls.__super__.get_by_key_name(key_name)
       memcache.add(key_name, entity, 3600)
       return entity

4 个答案:

答案 0 :(得分:2)

是否有意义取决于:

  1. 您的应用程序的性能是否不够好(您的性能目标是什么以及如何衡量?)
  2. 数据库查询是否真的是您的应用程序的瓶颈(性能问题实际上可能存在于其他地方,在您分析之前您不会知道)
  3. memcache查询是否实际上比数据库的缓存(如果有的话)更快以及多少(从数据库中重复查询相同的记录可能来自RAM)
  4. 你的应用程序的查询模式(如果记录不在memcache中,你实际上每个查询都要做更多工作,所以如果你的大多数查询都是唯一的,它甚至可能会更慢! - 数据库的缓存也可能就足够了)
  5. 有人可能已经为Google App Engine测量了其中一些,但#4仍然是你需要为你的应用程序找出的东西。换句话说:如果没有更多数据,这个问题就无法解决。但是,希望我已经给你一些地方开始调查。

    根据您对数据库和SQL的了解程度,您也可以通过更好地使用数据库来加快查询速度,而无需在应用程序中添加缓存的复杂性(对GAE知之甚少不够了解)它能让你做多少事情。)

    至于你提议的实现,它看起来并不合理,因为get_by_key_name()已经是一个类方法。您可能尝试将新方法直接注入现有的Model类(或将整个子类替换回模块),这样您就不需要更改任何使用{{{ 1}}。但这有其自身的危险。当然,你所拥有的是足够好的,你可以做一些测试,看看它是否真的有帮助。

答案 1 :(得分:2)

更好更整洁的解决方案是使用NDB,它内置了对memcache和实例内存缓存的支持。

答案 2 :(得分:1)

缓存的想法很好(尽管其他人已经表明你必须小心失效)。但是我不会覆盖get_by_name()来执行它。我会编写单独的函数来处理缓存,因此代码的读者可以清楚地看到你没有使用标准的get_by_name()。另请注意,get_by_name()是一个非常薄的层,位于带有Key对象的get()之上 - 您也应该提供该API。

答案 3 :(得分:0)

我也使用memcache来缓存实体,我认为加快数据库操作是个好主意。 我选择将get_key方法添加到类模型中,因为memcache / datastore代理可以在许多类中重用。

定义一般的memcache db proxy

#mydb.py
def get_cache(keys):
    """ not support async operation
    because Async operation conflict with cache logiclly 
    """
    if not isinstance(keys, list) and not isinstance(keys, tuple):
        keys = [keys]

    keys = [str(k) for k in keys]
    results = memcache.get_multi(keys) #@UndefinedVariable
    keys_not_in_cache = [k for k in keys if k not in results] 

    if keys_not_in_cache:
        values = db.get([db.Key(k) for k in keys_not_in_cache])
        results_from_db = dict(zip(keys_not_in_cache, values))
        results.update(results_from_db)
        memcache.set_multi(results_from_db) #@UndefinedVariable

    return [results[k] for k in keys]        

def put_cache(values):
    """ Not support async operation
    """
    if not isinstance(values, list):
        values = [values]

    db.put(values)

    keys_str = [(str(k.key()), k) for k in values]
    memcache.set_multi(dict(keys_str)) #@UndefinedVariable    

def delete_cache(values):
    """ Not Support Async Operation
    """
    if not isinstance(values, list):
        values = [values]

    db.delete(values)

    keys_str = [str(k.key()) for k in values]
    memcache.delete_multi(keys_str) #@UndefinedVariable

使用示例

# for the class want to use this feature
class User(db.Model):
    email = db.EmailProperty()

    @classmethod
    def get_key(cls, email):
        return db.Key.from_path(cls.__name__, email)

# Using memcache db proxy
user_keys = [User.get_key(USER_EMAIL_ADDRESS) for USER_EMAIL_ADDRESS in ALL_USER_EMAIL_ADDRESS]
users = mydb.get_cache(user_keys)