Google app engine 不同版本的应用程序引擎Memcache密钥前缀

Google app engine 不同版本的应用程序引擎Memcache密钥前缀,google-app-engine,memcached,versions,Google App Engine,Memcached,Versions,你好 我有一个谷歌应用引擎设置,其中memcached键的前缀是os.environ['CURRENT\u VERSION\u ID'],以便在部署时生成一个新的缓存,而不必手动刷新缓存 在开发需要同时运行两个版本的应用程序之前,这一切都很正常。当然,这会产生缓存中的不一致性 我现在正在寻找关于如何为键添加前缀的建议。本质上,当部署任何版本时,都需要有一个在不同版本之间变化的变量。(好吧,这不是很理想,因为缓存被完全破坏了。) 我在考虑以下可能性: 创建一个存储最新缓存前缀的RuntimeEn

你好

我有一个谷歌应用引擎设置,其中
memcached
键的前缀是
os.environ['CURRENT\u VERSION\u ID']
,以便在部署时生成一个新的缓存,而不必手动刷新缓存

在开发需要同时运行两个版本的应用程序之前,这一切都很正常。当然,这会产生缓存中的不一致性

我现在正在寻找关于如何为键添加前缀的建议。本质上,当部署任何版本时,都需要有一个在不同版本之间变化的变量。(好吧,这不是很理想,因为缓存被完全破坏了。)

我在考虑以下可能性:

  • 创建一个存储最新缓存前缀的
    RuntimeEnvironment
    实体。缺点:即使缓存,也会降低每个请求的速度。无法缓存在内存中,只能缓存在memcached中,因为其他版本的部署可能会更改它

  • 使用每个实体的版本号。这产生了非常好的粒度,因为缓存可以为未修改的实体保持温暖。缺点是,当模型更改时,我们需要推送到所有版本,为了在部署到生产环境之前测试模型更改,我希望避免这种情况

  • 忘记键前缀。键的全局命名空间。编写脚本以在每次部署时刷新缓存。这实际上似乎和第一个想法一样好(如果不是更好的话):缓存在两种情况下都会被完全破坏,而这一个避免了运行时实体的开销


任何想法,不同的想法,非常感谢

os.environ['CURRENT_VERSION_ID']值将与您的两个版本不同,因此您将为每个版本(实时版本和开发/测试版本)提供单独的缓存

所以,我假设您的问题是,当您“部署”一个版本时,您不希望使用来自开发/测试的缓存?(否则,就像Nick和systempuntoout一样,我很困惑)

实现这一点的一种方法是在缓存中使用域/主机头,因为这对于您的dev/live版本是不同的。您可以通过执行以下操作来提取主机:

scheme, netloc, path, query, fragment = urlparse.urlsplit(self.request.url)

# Discard any port number from the hostname
domain = netloc.split(':', 1)[0]

这不会给出特别好的键,但它可能会做您想要的事情(假设我理解正确)。

os.environ['CURRENT\u VERSION\u ID']值将与您的两个版本不同,因此您将为每个版本(活动版本和开发/测试版本)提供单独的缓存

所以,我假设您的问题是,当您“部署”一个版本时,您不希望使用来自开发/测试的缓存?(否则,就像Nick和systempuntoout一样,我很困惑)

实现这一点的一种方法是在缓存中使用域/主机头,因为这对于您的dev/live版本是不同的。您可以通过执行以下操作来提取主机:

scheme, netloc, path, query, fragment = urlparse.urlsplit(self.request.url)

# Discard any port number from the hostname
domain = netloc.split(':', 1)[0]

这不会给出特别好的键,但它可能会做你想做的事情(假设我理解正确)。

我对问题的措辞有点困惑

我最终得到了每类属性的散列。以这门课为例:

class CachedModel(db.Model):

  @classmethod
  def cacheVersion(cls):
    if not hasattr(cls, '__cacheVersion'):
      props = cls.properties()
      prop_keys = sorted(props.keys())
      fn = lambda p: '%s:%s' % (p, str(props[p].model_class))
      string = ','.join(map(fn, prop_keys))
      cls.__cacheVersion = hashlib.md5(string).hexdigest()[0:10]
    return cls.__cacheVersion

  @classmethod
  def cacheKey(cls, key):
    return '%s-%s' % (cls.cacheVersion(), str(key))
这样,当实体使用其
cacheKey(…)
保存到memcached时,只有在实际类相同的情况下,它们才会共享缓存

这还有一个额外的好处,即推送不修改模型的更新会保留该模型的所有缓存项不变。换句话说,推送更新不再充当刷新缓存的角色

这样做的缺点是,每个webapp实例对类进行一次散列

2011年3月9日更新:我改用了一种更复杂但更准确的方式来获取版本。使用
\uuuu dict\uuuu
产生了不正确的结果,因为它的
str
表示包含指针地址。这种新方法只考虑数据存储属性


2011年3月14日更新:所以python的哈希(…)显然不能保证在解释器运行之间相等。一个不同的应用程序引擎实例看到了不同的散列,这种情况很奇怪。现在使用md5(比sha1快,比SH256快)。它不需要真正的加密安全。只需要一个ok hashfn。可能会切换到使用更快的东西,但现在我宁愿没有错误。还确保了键被排序,而不是属性对象。

我对问题的措辞有点困惑

我最终得到了每类属性的散列。以这门课为例:

class CachedModel(db.Model):

  @classmethod
  def cacheVersion(cls):
    if not hasattr(cls, '__cacheVersion'):
      props = cls.properties()
      prop_keys = sorted(props.keys())
      fn = lambda p: '%s:%s' % (p, str(props[p].model_class))
      string = ','.join(map(fn, prop_keys))
      cls.__cacheVersion = hashlib.md5(string).hexdigest()[0:10]
    return cls.__cacheVersion

  @classmethod
  def cacheKey(cls, key):
    return '%s-%s' % (cls.cacheVersion(), str(key))
这样,当实体使用其
cacheKey(…)
保存到memcached时,只有在实际类相同的情况下,它们才会共享缓存

这还有一个额外的好处,即推送不修改模型的更新会保留该模型的所有缓存项不变。换句话说,推送更新不再充当刷新缓存的角色

这样做的缺点是,每个webapp实例对类进行一次散列

2011年3月9日更新:我改用了一种更复杂但更准确的方式来获取版本。使用
\uuuu dict\uuuu
产生了不正确的结果,因为它的
str
表示包含指针地址。这种新方法只考虑数据存储属性


2011年3月14日更新:所以python的哈希(…)显然不能保证在解释器运行之间相等。一个不同的应用程序引擎实例看到了不同的散列,这种情况很奇怪。现在使用md5(比sha1快,比SH256快)。它不需要真正的加密安全。只需要一个ok hashfn。可能会切换到使用更快的东西,但现在我宁愿没有错误。还确保对键进行了排序,而不是属性对象。

我不明白;既然您在缓存键前面加了
os.environ['CURRENT\u VERSION\u ID']
,那么两个不同的版本在缓存中怎么会不一致呢?