如何在GAE应用程序中缓存进程中经常使用的数据?

时间:2017-03-07 16:46:49

标签: python google-app-engine memcached

在Google App Engine中,无法在memcache中存储(整体而言)大于1 MB的对象。

假设我想要缓存数据存储区查询的结果,该查询包含1000条记录,每条记录5 KB,总计约5 MB。

如何进行?我可以在Web应用程序的Python过程中缓存此数据,而不是使用memcache吗?例如,在全局变量中?

请在下面找到我的答案。让我知道你的想法。

1 个答案:

答案 0 :(得分:2)

Google App Engine可以解析针对不同进程甚至不同物理机的不同Web请求。这意味着在不同请求之间维护全局状态有点困难,即实现数据的本地缓存。

当数据修改发生时,您必须小心使本地缓存无效 - 在所有进程上(缓存一致性问题)。

此外,如果您的GAE应用程序定义为threadsafe,则单个进程可以在不同的线程中同时处理多个请求。

我勾画出一个可能的解决方案:

  • 使用全局字典保存数据
  • 使用全局词典跟踪进程内数据的版本
  • gold 版本的数据保存在微小的memcache记录中(当然只有版本标记,而不是实际数据)
  • 当进程内本地数据过时(无效)时,从 gold 存储中获取(通过value_provider函数)
  • 在适当的时候,使所有计算机之间的进程内数据无效(通过重置 gold 版本标记)。

以下是代码:

import threading
from uuid import uuid4
from google.appengine.api import memcache

_data = dict()
_versions = dict()
lock = threading.Lock()

TIME = 60 * 10  # 10 minutes


def get(key, value_provider):
    """
    Gets a value from the in-process storage (cache).
    If the value is not available in the in-process storage
    or it is invalid (stale), then it is fetched by calling the 'value provider'.
    """
    # Fast check, read-only step (no critical section).
    if _is_valid(key):
        return _data[key]

    # Data is stale (invalid). Perform read+write step (critical section).
    with lock:
        # Check again in case another thread just left the critical section
        # and brought the in-process data to a valid state.
        if _is_valid(key):
            return _data[key]

        version = memcache.get(key)

        # If memcache entry is not initialized
        if not version:
            version = uuid4()
            memcache.set(key, version, time=TIME)

        _data[key] = value_provider()
        _versions[key] = version

    return _data[key]


def _is_valid(key):
    """Whether the in-process data has the latest version (according to memcache entry)."""
    memcache_version = memcache.get(key)
    proc_version = _versions.get(key, None)
    return memcache_version and memcache_version == proc_version


def invalidate(key):
    """Invalidates the in-process cache for all processes."""
    memcache.set(key, uuid4(), time=TIME)

<强>参考文献:

https://softwareengineering.stackexchange.com/a/222818

Understanding global object persistence in Python WSGI apps

Problem declaring global variable in python/GAE

Python Threads - Critical Section

https://en.wikipedia.org/wiki/Cache_coherence