将 Memcache 迁移到 Memorystore

在执行某些任务时,高性能的可扩缩 Python Web 应用通常使用内存中的分布式数据缓存,而不是可靠的永久性存储空间。

App Engine 对此的解决方案是 Memcache,这是一个内存中的分布式数据存储区,可用作特定任务的缓存。

从旧版捆绑服务迁出时,建议将 App Engine Memcache 替换为 Memorystore,它是一种全代管式的云端缓存服务,支持开源缓存引擎、Redis 和 Memcached。本指南介绍了如何使用 Memorystore for Redis,它可以构建可实现亚毫秒级数据访问的应用缓存。

如果您的 Python 应用使用 Memcache 仅减少 ndb 或 Cloud NDB 请求的延迟时间,您可以使用 Cloud NDB 对 Redis 的内置支持,而不是 Memcache 或 Memorystore for Redis。

开始之前,请确保您的应用不会超出 Memorystore for Redis 配额

何时为 Python 应用使用内存缓存

在 Python 应用中,会话数据、用户偏好设置以及网页查询返回的其他数据都非常适合进行缓存。通常,如果频繁运行的查询所返回的结果集不需要立即显示在您的应用中,便可以缓存结果。如此,后续请求可以检查缓存,只有当结果缺失或过期时才会查询数据库。

如果您将某个值仅存储在 Memorystore 中,而没有将其备份到永久性存储空间,请确保在该值过期及从缓存中移除时,您的应用仍可正常运作。例如,如果用户会话数据的突然缺失导致会话出现故障,则应考虑除了在 Memorystore 中存储该数据之外,还应将其存储在数据库中。

须知事项

如果尚未设置,请设置 Python 开发环境以使用与 Google Cloud 兼容的 Python 版本,并安装用于创建独立 Python 环境的测试工具。

了解 Memorystore 权限

与 Google Cloud 服务之间进行的每一次交互操作都需要经过授权。例如,如需与 Memorystore 托管的 Redis 数据库进行交互,您的应用需要提供有权访问 Memorystore 的账号的相应凭据。

默认情况下,您的应用会提供 App Engine 默认服务账号的凭据,该账号有权访问您的应用所在项目中的数据库。

如果满足以下任何条件,则您需要使用明确提供凭据的备用身份验证技术:

  • 您的应用和 Memorystore 数据库位于不同的 Google Cloud 项目中。

  • 您已更改分配给默认 App Engine 服务账号的角色。

如需了解备用身份验证技术,请参阅为服务器到服务器的生产应用设置身份验证

迁移过程概览

如需在 Python 应用中使用 Memorystore 而不是 Memcache,请执行以下操作:

  1. 设置 Memorystore for Redis,此操作需要您在 Memorystore 上创建 Redis 实例并创建无服务器 VPC 访问通道,以供您的应用与 Redis 实例通信。 创建这两个独立实体的顺序并不严格,可以按任意顺序设置。本指南中的说明首先显示如何设置无服务器 VPC 访问通道。

  2. 安装适用于 Redis 的客户端库并使用 Redis 命令缓存数据。

    Memorystore for Redis 与适用于 Redis 的任何客户端库都兼容。

    本指南介绍如何使用 redis-py 客户端库从您的应用发送 Redis 命令。

  3. 测试您的更新

  4. 将应用部署到 App Engine

设置 Memorystore for Redis

如需设置 Memorystore for Redis,请执行以下操作:

  1. 将 App Engine 连接到 VPC 网络。您的应用只能通过 VPC 连接器与 Memorystore 通信。

    请务必按照将应用配置为使用连接器中的说明,将 VPC 连接信息添加到 app.yaml 文件中。

  2. 记下您创建的 Redis 实例的 IP 地址和端口号。您在自己的代码中创建 Redis 客户端时,将会用到这些信息。

  3. 在 Memorystore 中创建 Redis 实例

    当系统提示您为 Redis 实例选择区域时,请选择您的 App Engine 应用所在的区域

安装依赖项

如需使用 redis-py 客户端库,请执行以下操作:

  1. 更新 app.yaml 文件。 按照适用于您的 Python 版本的说明操作:

    Python 2

    对于 Python 2 应用,请添加最新版本的 grpciosetuptools 库。

    下面是一个 app.yaml 文件示例:

    runtime: python27
    threadsafe: yes
    api_version: 1
    
    libraries:
    - name: grpcio
      version: latest
    - name: setuptools
      version: latest
    

    Python 3

    对于 Python 3 应用,请在 app.yaml 文件中使用受支持的 Python 3 版本指定 runtime 元素。例如:

    runtime: python310 # or another support version
    

    Python 3 运行时会自动安装库,因此您无需指定过往 Python 2 运行时中的内置库。如果您的 Python 3 应用在迁移时使用其他旧版捆绑服务,您可以继续指定必要的内置库。否则,您可以删除 app.yaml 文件中的不必要行。

  2. 更新 requirements.txt 文件。 按照适用于您的 Python 版本的说明操作:

    Python 2

    将 Memorystore for Redis 的 Cloud 客户端库添加到 requirements.txt 文件中的依赖项列表。

    redis
    

    运行 pip install -t lib -r requirements.txt 以更新应用的可用库列表。

    Python 3

    将 Memorystore for Redis 的 Cloud 客户端库添加到 requirements.txt 文件中的依赖项列表。

    redis
    

    App Engine 会在 Python 3 运行时的应用部署期间自动安装这些依赖项,因此如果存在 lib 文件夹,请删除它。

  3. 对于 Python 2 应用,如果您的应用使用 lib 目录中指定的内置库或复制的库,您必须在 appengine_config.py 文件(与 app.yaml 文件位于同一文件夹)中指定这些路径:

    import pkg_resources
    from google.appengine.ext import vendor
    
    # Set PATH to your libraries folder.
    PATH = 'lib'
    # Add libraries installed in the PATH folder.
    vendor.add(PATH)
    # Add libraries to pkg_resources working set to find the distribution.
    pkg_resources.working_set.add_entry(PATH)
    

创建 Redis 客户端

如需与 Redis 数据库进行交互,您的代码需要创建 Redis 客户端才能管理与 Redis 数据库的连接。以下部分介绍如何使用 redis-py 客户端库创建 Redis 客户端。

指定环境变量

redis-py 客户端库使用两个环境变量为您的 Redis 数据库组建网址:

  • 用于标识您在 Memorystore 中创建的 Redis 数据库的 IP 地址的变量。
  • 用于标识您在 Memorystore 中创建的 Redis 数据库的端口号的变量。

我们建议您在应用的 app.yaml 文件中定义这些变量,而不是直接在您的代码中定义这些变量。这样可以更轻松地在不同的环境(例如本地环境和 App Engine)中运行您的应用。

例如,请将下面几行内容添加到 app.yaml 文件中:

 env_variables:
      REDISHOST: '10.112.12.112'
      REDISPORT: '6379'

导入 redis-py 并创建客户端

定义 REDISHOSTREDISPORT 环境变量后,请使用下面几行代码导入 redis-py 库并创建客户端:

  import redis

  redis_host = os.environ.get('REDISHOST', 'localhost')
  redis_port = int(os.environ.get('REDISPORT', 6379))
  redis_client = redis.Redis(host=redis_host, port=redis_port)

如果您对其他应用使用了旧版 redis-py,则可能使用过 StrictClient 类,而不是 Client。但是,redis-py 现在建议使用 Client 而不是 StrictClient

使用 Redis 命令在缓存中存储和检索数据

虽然 Memorystore Redis 数据库支持大多数 Redis 命令,但您只需使用几个命令即可在缓存中存储和检索数据。下表建议了一些可用于缓存数据的 Redis 命令。如需了解如何从您的应用调用这些命令,请参阅客户端库的文档。

请注意,对于 Python 2 应用,虽然 Memcache 为其许多命令提供了异步替代选项,但 redis-py 客户端库并非总是提供等效的异步方法。如果您要求与缓存的所有交互都是异步的,则可以使用其他 Python 版 Redis 客户端库

任务 Redis 命令
在数据缓存中创建一个条目,
并为该条目设置到期时间
SETNX
MSETNX
从缓存中检索数据 GET
MGET
替换现有的缓存值 SET
MSET
递增或递减缓存数值 INCR
INCRBY
DECR
DECRBY
从缓存中删除条目 DEL
UNLINK
支持与缓存进行并发交互(比较和设置 请参阅有关 Redis 事务的详细信息。 请注意,`redis-py` 客户端库要求所有事务都在流水线中进行。

测试更新

当您在本地测试应用时,请考虑运行 Redis 的本地实例以避免与生产数据交互(Memorystore 不提供模拟器)。如需在本地安装并运行 Redis,请按照 Redis 文档中的说明进行操作。请注意,目前无法在 Windows 上本地运行 Redis。

如需详细了解如何测试 Python 应用,请参阅使用本地开发服务器

部署应用

一旦您的应用能够在本地开发服务器上无错误地正常运行,请执行以下操作:

  1. 在 App Engine 上测试应用

  2. 如果应用无错误地正常运行,请使用流量拆分功能为更新后的应用缓慢增加流量。请先仔细监控应用是否存在任何数据库问题,然后再将更多流量路由到更新后的应用。

后续步骤