跨版本的 App Engine Memcache 键前缀

发布于 2024-10-18 12:45:47 字数 666 浏览 1 评论 0原文

问候!

我有一个 Google App Engine 设置,其中 memcached 键以 os.environ['CURRENT_VERSION_ID'] 为前缀,以便在部署时生成新的缓存,而无需手动刷新缓存。

这一直工作得很好,直到开发需要同时运行应用程序的两个版本。当然,这会导致缓存不一致。

我现在正在寻找有关如何为键添加前缀的建议。本质上,需要有一个在部署任何版本时跨版本变化的变量。 (嗯,这不太理想,因为缓存完全被耗尽。)

我正在考虑以下可能性:

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

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

  • 忘记键前缀。键的全局命名空间。编写一个脚本以在每次部署时刷新缓存。这实际上看起来与第一个想法一样好,甚至更好:在两种情况下缓存都被完全耗尽,而这个避免了运行时实体的开销。

任何想法、不同的想法都非常感谢!

Greetings!

I've got a Google App Engine Setup where memcached keys are prefixed with os.environ['CURRENT_VERSION_ID'] in order to produce a new cache on deploy, without having to flush the cache manually.

This was working just fine until it became necessary for development to run two versions of the application at the same time. This, of course, is yielding inconsistencies in caching.

I'm looking for suggestions as to how to prefix the keys now. Essentially, there needs to be a variable that changes across versions when any version is deployed. (Well, this isn't quite ideal, as the cache gets totally blown out.)

I was thinking of the following possibilities:

  • Make a RuntimeEnvironment entity that stores the latest cache prefix. Drawbacks: even if cached, slows down every request. Cannot be cached in memory, only in memcached, as deployment of other version may change it.

  • Use a per-entity version number. This yields very nice granularity in that the cache can stay warm for non-modified entities. The downside is we'd need to push to all versions when models are changed, which I want to avoid in order to test model changes out before deploying to production.

  • Forget key prefix. Global namespace for keys. Write a script to flush the cache on every deploy. This actually seems just as good as, if not better than, the first idea: the cache is totally blown in both scenarios, and this one avoids the overhead of the runtime entity.

Any thoughts, different ideas greatly appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏日落 2024-10-25 12:45:47

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

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

实现此目的的一种方法是使用缓存中的域/主机标头 - 因为这对于您的开发/实时版本是不同的。您可以通过执行以下操作来提取主机:

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

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

这不会提供特别好的密钥,但它可能会执行您想要的操作(假设我理解正确)。

The os.environ['CURRENT_VERSION_ID'] value will be different to your two versions, so you will have separate caches for each one (the live one, and the dev/testing one).

So, I assume your problem is that when you "deploy" a version, you do not want the cache from development/testing to be used? (otherwise, like Nick and systempuntoout, I'm confused).

One way of achieving this would be to use the domain/host header in the cache - since this is different for your dev/live versions. You can extract the host by doing something like this:

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

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

This won't give particularly nice keys, but it'll probably do what you want (assuming I understood correctly).

£噩梦荏苒 2024-10-25 12:45:47

我对这个问题的措辞有点困惑。

我最终选择了每类属性的哈希值。以此类为例:

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 时,仅当实际类相同时,它们才会共享缓存。

这还有一个额外的好处,即推送不修改模型的更新,使该模型的所有缓存条目保持不变。换句话说,推送更新不再充当刷新缓存的作用。

这样做的缺点是每个 Web 应用实例都会对类进行一次哈希处理。

2011-3-9 更新:我更改为更复杂但更准确的获取版本的方式。结果使用 __dict__ 产生了错误的结果,因为它的 str 表示形式包含指针地址。这种新方法只考虑数据存储属性。

2011-3-14 更新:所以 python 的 hash(...) 显然不能保证在解释器运行之间相等。遇到奇怪的情况,不同的应用程序引擎实例看到不同的哈希值。现在使用 md5(比 sha1 更快,比 sha256 更快)。没有真正需要它是加密安全的。只需要一个好的 hashfn 即可。可能会改用更快的东西,但现在我宁愿没有错误。还确保对键进行排序,而不是对属性对象进行排序。

There was a bit of confusion with how i worded the question.

I ended up going for a per-class hash of attributes. Take this class for example:

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))

That way, when entities are saved to memcached using their cacheKey(...), they will share the cache only if the actual class is the same.

This also has the added benefit that pushing an update that does not modify a model, leaves all cache entries for that model intact. In other words, pushing an update no longer acts as flushing the cache.

This has the disadvantage of hashing the class once per instance of the webapp.

UPDATE on 2011-3-9: I changed to a more involved but more accurate way of getting the version. Turns out using __dict__ yielded incorrect results as its str representation includes pointer addresses. This new approach just considers the datastore properties.

UPDATE on 2011-3-14: So python's hash(...) is apparently not guaranteed to be equal between runs of the interpreter. Was getting weird cases where a different app engine instance was seeing different hashes. using md5 (which is faster than sha1 faster than sha256) for now. no real need for it to be crypto-secure. just need an ok hashfn. Will probably switch to use something faster, but for now i rather be bugfree. Also ensured keys were getting sorted, not the property objects.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文