首页 > 解决方案 > 对 memcache 将 AppEngine py2.7 应用程序迁移到 py3 感到困惑

问题描述

我有一个在旧版 appengine 2.7 中运行的游戏服务器。我已将服务器迁移到 py3/flask 和所有各种位。我已将新服务器连接到 Redis 实例,而旧服务器正在使用 py2.7 的 memcache。

我正在考虑将我的服务器的 2.7 版本连接到 Redis 内存缓存,因为我已经将它作为分阶段迁移运行。这样我可以在 py3 服务器和 py2 服务器之间拆分流量,它们将使用与我测试等相同的 memcache 服务器。我可以让一些 beta 用户与新服务器交谈并与当前服务器共存。

我有一个版本的 py2.7 服务器与 redis 通信。但我发现使用 Redis 的文档对于存储 ndb 模型有点混乱。看来我不能像使用旧的遗留 memcache 那样直接在 Redis 中填充 ndb 模型类。

在迁移文档中,它说您可以使用以下示例将 redis 设置为 appengine 的“全局缓存”:

client = ndb.Client()
global_cache = ndb.RedisCache.from_environment()

with client.context(global_cache=global_cache):
  books = Book.query()
  for book in books:
      print(book.to_dict())

我不是很清楚这意味着什么。我是否需要以我想要缓存的方式构建所有查询,或者是否有一次性设置,然后模型将自动缓存?如果存在,上面的示例会自动从缓存中提取吗?

目前在旧版 memcache 服务器中,我将一堆模型实例(或在我的情况下是特定用户所属的游戏)收集到 python 列表中,并使用如下键缓存它们

cacheKey = userskey.urlsafe()+"_gamesList"

每当该用户的游戏以某种方式更改(更新、删除、添加..等)时,我都会删除 cacheKey.. 下次用户查询他们的游戏列表时,我会重建缓存。看起来我不能在 Redis 中简单地存储这样的数据。此外,由于该用户可能与服务器交互,因此我只想要代表该用户缓存的模型..每次该用户与我的服务器交谈时,我都需要使用密钥调用他们的用户帐户

我想我只是对全局缓存以及这一切与旧版内存缓存有何不同感到困惑。目前,我使用旧版 memcache 获得了接近 90% 的缓存命中率,因此尝试使用 Redis 复制它当然是值得的。甚至可能只是一个指向实际示例应用程序的指针也会有所帮助。令人惊讶的是,我没有找到那个。

标签: pythongoogle-app-enginegoogle-app-engine-python

解决方案


术语“全局缓存”有点令人困惑,它只是意味着可以从项目外部访问 MemoryStore Redis 实例。
如果您想继续使用 NDB,则需要先迁移到 CloudNDB。回答您的一个问题 - 不,MemoryStore 不会自动缓存任何内容。

但是我的建议是——如果你所做的只是在 Redis 中存储键值对,为什么不直接使用本机 Redis 功能呢?

# Connect to Redis (I create a CloudDNS record which points to the private IP)
pool = redis.ConnectionPool(host=<REDIS_HOST>, port=<REDIS_PORT>, db=0)
r = redis.Redis(connection_pool=pool)

然后您可以获取对象并将其设置为字节

import pickle, io

f = io.BytesIO()
pickle.dump(book.to_dict(),f)
f.seek(0)

res = r.set(alias,f.read())
# res will be True or False

outObj = r.get(alias)
if len(outObj) > 0:
    dictObj = pickle.loads(outObj)
else:
   # Cache Miss - get it from the DB and store it in Redis

另外MemoryStore很贵,我用FakeRedis本地测试

import fakeredis as redis
serv = redis.FakeServer()
r = redis.FakeStrictRedis(server=serv)

更新 - 从您关于 UnicodeDecodeError 的评论中,我不知道您的字典中有哪些数据会导致问题,您可以尝试转换为 json,对于任何不可序列化的内容(如 datetime 对象),只需将它们转换为字符串

jsonObj = json.dumps(dictObj, default=str)
f = io.BytesIO()
pickle.dump(jsonObj,f)
f.seek(0)


推荐阅读