如何在 Flask 应用中使用 App Engine Memcache(模块 12)

1. 概览

无服务器迁移站系列 Codelab(自定进度的动手教程)和相关视频旨在帮助 Google Cloud 无服务器开发者通过一次或多次迁移(主要是从旧版服务迁移)来指导他们的应用现代化。这样做可让您的应用更易于移植,并为您提供更多选择和灵活性,使您能够与更多 Cloud 产品集成并访问这些产品,还能更轻松地升级到新的语言版本。虽然最初侧重于最早的 Cloud 用户(主要是 App Engine [标准环境] 开发者),但本系列文章的范围足够广,可涵盖其他无服务器平台(例如 Cloud FunctionsCloud Run),或者其他平台(如果适用)。

本 Codelab 将介绍如何将 App Engine Memcache 纳入 模块 1 Codelab 中的示例应用并加以使用。我们在本模块 12 教程中添加了 Memcache 的使用,然后在模块 13 中迁移到 Cloud Memorystore

在接下来的实验中

  • 使用 App Engine Memcache API/库
  • 向基本的 Python 2 Flask App Engine NDB 应用添加缓存

所需条件

调查问卷

您将如何使用本教程?

仅阅读教程内容 阅读并完成练习

您如何评价使用 Python 的体验?

新手水平 中等水平 熟练水平

您如何评价自己在使用 Google Cloud 服务方面的经验水平?

新手水平 中等水平 熟练水平

2. 背景

为了从 App Engine Memcache 进行迁移,请将它的使用情况添加到模块 1 Codelab 中生成的现有 Flask 和 App Engine NDB 应用。示例应用会向用户显示最近的 10 次访问。如果同一用户刷新浏览器,持续创建新的 Visit 实体并从 Datastore 中提取最近的访问记录并非最佳做法,因此我们将缓存这些最近的访问记录。

如果同一位访问者再次访问该网页,则系统会从缓存中返回这些访问。如果新用户访问该网站或一小时后,系统会清空缓存并将其替换为最新条目(更不用说注册新的访问)。在实现此 App Engine Memcache 集成后,我们可以在下一个 Codelab(模块 13)中将其迁移到 Cloud Memorystore

本教程包含以下步骤:

  1. 设置/准备工作
  2. 更新配置
  3. 修改应用代码

3. 设置/准备工作

在开始学习本教程的主要部分之前,让我们设置项目、获取代码,然后部署基准应用,以便我们知道我们从工作代码开始。

1. 设置项目

如果您已完成模块 1 Codelab,我们建议您重复使用同一项目(和代码)。或者,您可以创建一个全新的项目或重复使用另一个现有项目。确保该项目具有有效的结算账号,并且已启用 App Engine。

2. 获取基准示例应用

此 Codelab 的先决条件之一是拥有一个工作正常的模块 1 示例应用。如果您没有,请先完成其中一个教程(上面的链接),然后再继续学习。或者,如果您已经熟悉其内容,可以直接从下面的模块 1 代码开始。

无论您是使用自己的代码还是我们的代码,我们都能在模块 1 中。本 Codelab 将引导您完成每个步骤,最后获得类似于模块 11 代码库文件夹 (FINISH) 中的代码。

模块 1 启动文件(您或我们的文件)的目录应如下所示:

$ ls
README.md               main.py                 templates
app.yaml                requirements.txt

3. (重新)部署基准应用

您现在需要执行的剩余预处理步骤:

  1. 重新熟悉 gcloud 命令行工具
  2. 使用 gcloud app deploy 重新部署示例应用
  3. 确认应用在 App Engine 上运行没有任何问题

成功执行完这些步骤并看到您的 Web 应用正常运行(输出类似于下方所示)后,您就可以为应用添加缓存使用功能了。

a7a9d2b80d706a2b.png

4. 更新配置

无需对标准 App Engine 配置文件(app.yamlrequirements.txtappengine_config.py)进行任何更改。

5. 修改应用文件

由于我们只添加了 App Engine API,因此不涉及任何外部软件包,这意味着无需更新任何配置文件(app.yamlrequirements.txtappengine_config.py)。只有一个应用文件 main.py,因此本部分中的所有更改都只会影响该文件。

导入

最重要的一步是导入 Memcache 库 google.appengine.api.memcache。由于我们要将最近 1 小时的访问记录缓存起来,因此我们还要添加一个常量来表示 1 小时内的秒数。以下是您的代码在进行此项更改前后的样子:

之前

from flask import Flask, render_template, request
from google.appengine.ext import ndb

app = Flask(__name__)

升级后

from flask import Flask, render_template, request
from google.appengine.api import memcache
from google.appengine.ext import ndb

app = Flask(__name__)
HOUR = 3600

添加了对 Memcache 的缓存支持

最显著的变化是在应用中添加了缓存的使用。更具体地说,我们应该缓存最近的访问,检查是否有缓存的访问,并尽可能根据我们的计划使用缓存的结果。应用将采取以下步骤来实现我们的目标:

  1. 设置当前访问会话并将其命名为 visitor
  2. 尝试从缓存中提取最新的 visits
  3. 如果缓存为空或最新访问者 (visits[0]['visitor']) 与当前 visitor 不同:存储此最新访问,提取最近的访问,并缓存这些访问一个小时。
  4. 通过 Web 模板向用户显示 visits

下面是应用这些更新前后的效果:

之前

@app.route('/')
def root():
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10)
    return render_template('index.html', visits=visits)

升级后

@app.route('/')
def root():
    'main application (GET) handler'
    # check for (hour-)cached visits
    ip_addr, usr_agt = request.remote_addr, request.user_agent
    visitor = '{}: {}'.format(ip_addr, usr_agt)
    visits = memcache.get('visits')

    # register visit & run DB query if cache empty or new visitor
    if not visits or visits[0]['visitor'] != visitor:
        store_visit(ip_addr, usr_agt)
        visits = list(fetch_visits(10))
        memcache.set('visits', visits, HOUR)  # set() not add()

    return render_template('index.html', visits=visits)

下图直观地展示了所做的更改:

b1242503602f7bf0.png

至此,我们已完成向模块 1 示例应用添加 App Engine memcache 使用所需的所有更改。接下来,我们来构建并部署此应用,看看它是否能正常运行!

6. 总结/清理

本部分将通过部署应用来结束此 Codelab,并验证应用是否按预期运行以及是否在任何反映的输出中正常运行。应用验证完成后,执行任何清理步骤,并考虑后续步骤。

部署并验证应用

使用 gcloud app deploy 重新部署应用,并确认应用可正常运行。您的代码现在应与 模块 12 文件夹中的 FINISH 内容相匹配。输出应与您之前部署的模块 1 应用完全相同:

a7a9d2b80d706a2b.png

我们只是加快了同一用户的用户体验。刷新时,您应直接从缓存中获取结果,这样既不会创建新的会话,也不会进行 Datastore 提取。

恭喜您完成了模块 12 的 Codelab,该 Codelab 介绍了如何向我们的示例应用添加对 App Engine memcache 服务的使用。现在,您可以选择在奖励步骤中将此 Python 2 应用移植到 Python 3。

清理

常规

如果您暂时不想继续操作,建议您停用 App Engine 应用,以免产生结算费用。不过,如果您想进一步测试或实验,App Engine 平台有免费配额,因此只要您不超过该使用层级,就不会产生费用。这是计算费用,但相关 App Engine 服务也可能会产生费用,因此请查看其价格页面了解详情。如果此迁移涉及其他 Cloud 服务,则这些服务会单独计费。在任何一种情况下,如果适用,请参阅下文中的“本 Codelab 特有的问题”部分。

为了完全公开透明,我们在此说明,部署到 Google Cloud 无服务器计算平台(例如 App Engine)会产生少量 build 和存储费用Cloud BuildCloud Storage 都有各自的免费配额。存储该图片会占用部分配额。不过,您可能居住在没有此类免费层的地区,因此请注意存储空间用量,以尽可能减少潜在费用。您应查看的特定 Cloud Storage“文件夹”包括:

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • 上述存储链接取决于您的 PROJECT_ID 和 *LOC*ation,例如,如果您的应用托管在美国,则为“us”。

另一方面,如果您不打算继续学习此应用或其他相关迁移 Codelab,并且想要彻底删除所有内容,请关闭您的项目

此 Codelab 特有的

以下列出的服务是此 Codelab 特有的。如需了解详情,请参阅各个产品的文档:

  • App Engine Memcache 服务有两种不同的版本,每种版本都有自己的价格结构,因此您必须跟踪与结算相关的用量。
  • App Engine Datastore 服务由 Cloud Datastore(Datastore 模式的 Cloud Firestore)提供,后者也提供免费层级;如需了解详情,请参阅其价格页面

后续步骤

下一个要考虑的逻辑迁移在模块 13 中介绍,该模块向开发者展示了如何从 App Engine memcache 服务迁移到 Cloud Memorystore。这些迁移都是可选的,适用于希望采取各种步骤来更新其应用的用户。Cloud Memorystore 服务是对 App Engine 的 memcache 的重大升级,原因如下:

  • Cloud Memorystore 不是无服务器的。这意味着您必须为缓存分配服务器。Cloud Memorystore 也没有免费层级。这两个因素都会对费用产生重大影响。
  • Cloud Memorystore 支持两种不同的底层存储机制(缓存引擎):RedisMemcached
  • 与 App Engine Memcache 相比,Cloud Memorystore(适用于 Redis)的功能集更加丰富和深入。
  • 如需使用 Cloud Memorystore,您必须设置 Cloud Memorystore 服务器,将其添加到 Google Cloud VPC 网络,然后让 App Engine 应用使用该网络与 Memorystore 服务器通信。

如果您认为自己不需要 Cloud Memorystore 提供的所有功能,或者担心它会对费用产生影响,则可以继续使用 App Engine Memcache。

除了模块 13 之外,还有许多其他可能的迁移,例如 Cloud NDB 和 Cloud Datastore,或 Cloud Tasks。此外,还可以跨产品迁移到 Cloud Run 和 Cloud Functions。您可以在迁移代码库中找到所有这些代码。

另一个可能的后续步骤是移植到 Python 3,下一部分将介绍此可选步骤。

7. 奖励:迁移到 Python 3

概览

本部分包含可选的奖励内容,用于将我们刚刚完成的模块 12 应用迁移到 Python 3。我们先介绍配置,然后再介绍应用。

简化 app.yaml

Python 3 运行时的一大优势是,app.yaml 可以大幅简化。

之前

以下是第 12 模块结束时 app.yaml 中的内容:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

由于 Python 3 运行时要求 Web 框架自行进行路由,因此 app.yaml 中的所有路由处理程序都必须更改为 auto。如果没有提供任何静态文件,用户可以直接移除整个 handlers: 部分。此外,threadsafeapi_version 都已弃用

升级后

在进行上述必需的更改后,以下是 Python 3 的替代 app.yaml

runtime: python39
app_engine_apis: true

唯一需要解释的行是 app_engine_apis: true2021 年旧版 App Engine 服务可用于第二代运行时时,部分运行时(包括 Python 3)需要额外的引导加载程序才能访问 ndbtaskqueuememcache 等 API。配置中的这一行可实现此目的。

更新 requirements.txt

requirements.txt 中,需要对原始 API 进行另一次引导启动:必须包含对新 App Engine SDK 的访问权限。

之前

以下是第 12 模块结束时 app.yaml 中的内容:

flask

升级后

只需添加 App Engine Python SDK,您就应该会看到以下内容:

flask
appengine-python-standard

删除 appengine_config.py 和 lib

新一代 App Engine 运行时改进了第三方软件包的使用方式:

  • 内置库是指经过 Google 审核并可在 App Engine 服务器上使用的库,这可能是因为它们包含开发者不允许部署到云端的 C/C++ 代码,这些库在第 2 代运行时中不再可用。
  • 在第二代运行时中,不再需要复制非内置库(有时称为“供应商”或“自打包”)。相反,它们应列在 requirements.txt 中,以便构建系统在部署时自动为您安装它们。

由于对第三方软件包管理进行了这些更改,因此不再需要 appengine_config.py 文件和 lib 文件夹,请将其删除。在第二代运行时中,App Engine 会自动安装 requirements.txt 中列出的第三方软件包。总结:

  1. 没有自捆绑或复制的第三方库;请在 requirements.txt 中列出它们
  2. 没有 pip installlib 文件夹中,即无 lib 文件夹期限
  3. app.yaml 中未列出内置第三方库(因此没有 libraries 部分);在 requirements.txt 中列出这些库
  4. 如果您的应用无需引用任何第三方库,则无需 appengine_config.py 文件

requirements.txt 中列出所有所需的第三方库是开发者的唯一要求。

更新应用以使用 App Engine SDK

如上所述,Python 3 应用需要进行一些修改才能访问 App Engine 捆绑服务:

  1. 捆绑 App Engine SDK(在 requirements.txt 中)
  2. 激活 App Engine SDK(在 app.yaml 中)
  3. 封装 WSGI 对象(在 main.py 中)

前两个配对已在上面完成,因此最后一个要求是更新 main.py

之前

以下是模块 12 结束时的 Python 2 main.py

from flask import Flask, render_template, request
from google.appengine.api import memcache
from google.appengine.ext import ndb

app = Flask(__name__)
HOUR = 3600

升级后

对于 Python 3 移植,请导入 SDK 并使用它(SDK 封装容器)封装 Flask 应用对象,如下所示:

from flask import Flask, render_template, request
from google.appengine.api import memcache, wrap_wsgi_app
from google.appengine.ext import ndb

app = Flask(__name__)
app.wsgi_app = wrap_wsgi_app(app.wsgi_app)
HOUR = 3600

开发者在从 2.x 向 3.x 移植 Python 应用时,需要进行这些更改才能访问捆绑服务。如果您未使用 Flask,文档中还提供了 Django 和 Pyramid 示例。如果您的 Python 2 代码不是 Web 应用,那么在移植到 Python 3 时,只需包含 SDK 软件包即可。我们的应用代码最初是为在 Python 2 和 3 下运行而精心设计的,因此无需进行额外的兼容性更改。

部署应用

完成上述更改后,您可以部署更新后的示例应用。(在同一 GCP 项目中,将应用的 Python 3 版本部署到原始 Python 2 版本上不会出现问题。)应用行为应保持不变。如果您需要将更新后的应用与我们的应用进行比较,请参阅迁移代码库中的模块 12b 文件夹。如需详细了解最新运行时(例如 Python 3)中对 App Engine 捆绑服务的支持,请参阅功能发布公告以及模块 17 Codelab

恭喜您完成了第 12 模块中的奖励步骤!另请参阅有关为 Python 3 运行时准备配置文件的文档。请参阅上文中的“总结/清理”部分,了解后续步骤和清理操作。

8. 其他资源

下面列出了其他资源,可供开发者进一步探索本迁移模块或相关迁移模块以及相关产品。这包括提供有关此内容的反馈的途径、指向代码的链接,以及您可能会觉得有用的各种文档。

Codelab 问题/反馈

如果您发现本 Codelab 存在任何问题,请先搜索您的问题,然后再提交。用于搜索和创建新问题的链接:

迁移时可参考的资源

下表中提供了指向模块 2(开始)和模块 12(结束)的代码库文件夹的链接。您还可以从所有 App Engine Codelab 迁移的代码库中访问这些示例,您可以克隆该代码库或下载 ZIP 文件。

Codelab

Python 2

Python 3

模块 1

代码

代码(本教程中未介绍)

第 12 模块(本 Codelab)

代码

代码

在线参考

以下是一些可能与本教程相关的在线资源:

App Engine

Cloud Memorystore 和 Cloud Datastore

其他云信息

视频

许可

此作品已获得 Creative Commons Attribution 2.0 通用许可授权。