python - 对 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 复制它当然是值得的。甚至可能只是一个指向实际示例应用程序的指针也会有所帮助。令人惊讶的是,我没有找到那个。
解决方案
术语“全局缓存”有点令人困惑,它只是意味着可以从项目外部访问 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)
推荐阅读
- javascript - 如何使用柏树在输入字段中仅键入随机字母
- javascript - 使用 jQuery .keydown() 插入字符后继续输入
- php - Laravel 贝宝支付。如何使它完整?它返回 json 响应
- javascript - 即使在重新加载页面后如何存储输入值?
- matlab - 方差作为matlab中高斯过程回归(fitrgp)函数的输入
- angular - 无法在项目数据更改后立即在 ng-select 中设置选定值,但它在第二次尝试时有效。反应形式
- java - Java 格式日期时间从 "dd/MM/yyyy HH:mm:ss" 到 "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
- html - 为什么不应用此 CSS 规则?
- epplus - 如何将新单元格附加到一行?
- php - 如何求和/获取总价 laravel 上的所有价格