1. 概览
这一系列的 Codelab(自定进度的动手教程)旨在帮助 Google App Engine(标准)开发者通过一系列迁移来指导他们的应用现代化。此类迁移大多涉及摆脱原始的运行时捆绑服务,因为下一代运行时更加灵活,为用户提供了更多的服务选项。另一种应用现代化方式是升级到新产品,而这正是本 Codelab 的主题。
如果 App Engine 用户使用 Cloud NDB 或 Cloud Datastore 客户端库访问 Datastore,则无需进一步迁移。不过,Cloud Firestore 是一种最新的可扩缩、高可用性 NoSQL 数据存储区,具有 Firebase 实时数据库的功能。
如果您是一位开发者,并且迫切希望使用 Firestore 来充分利用其功能,或者至少有足够的兴趣来探索迁移所涉及的内容,那么您来对地方了。本教程介绍如何将使用 Cloud Datastore 的 App Engine 应用迁移到 Cloud Firestore。
您将了解如何
- 了解 Datastore 与 Firestore 之间的区别
- 从 Cloud Datastore 迁移到 Cloud Firestore
所需条件
- 符合以下条件的 Google Cloud Platform 项目:
- 基本 Python 技能
- 常用 Linux 命令的实践知识
- 具备开发和部署 App Engine 应用的基础知识
- 我们建议您在学习本模块(模块 6)之前完成模块 3 Codelab,包括将其移植到 Python 3。
- 有效的模块 3 Cloud Datastore Python 3 App Engine 应用。
调查问卷
如何使用此 Codelab?
2. 背景
App Engine 的 Datastore 于 2013 年成为独立产品,即 Google Cloud Datastore,现在 App Engine 之外的开发者也可以使用它。第二年,Firebase 被 Google 收购。当时,它以实时数据库而闻名。
在接下来的几年里,Firebase 和 Cloud Datastore 团队致力于将一些 Firebase 功能集成到 Datastore 中。因此,在 2017 年,下一代 Cloud Datastore 发布。为了体现继承了部分 Firebase 功能,它更名为 Cloud Firestore。
Cloud Firestore 成为 Google Cloud 项目的默认 NoSQL 存储机制。新应用可以原生使用 Cloud Firestore,而现有的 Datastore 数据库已在后台转换为 Firestore,现在以“Datastore 模式下的 Firestore”运行,以保持与 Datastore 操作的兼容性。因此,应用只能在其中一种模式下运行 Cloud Firestore,并且一旦设置,便无法更改。
目前,当用户创建新项目并选择 NoSQL 解决方案时,系统会提示他们选择 Datastore 模式 Firestore 或原生模式 Firestore。用户添加 Datastore 实体后,无法再更改为 Firestore;同样,选择 Firestore 原生模式后,也无法再切换回 Datastore(或者说 Datastore 模式 Firestore)。如需了解详情,请参阅文档中的选择 Datastore 模式下的 Cloud Firestore 或原生 Firestore 模式页面。如需将应用迁移到 Firestore,必须先创建一个新项目,然后导出 Datastore 并将其导入 Firestore。本教程旨在让开发者了解使用 Cloud Datastore 和 Cloud Firestore 之间的区别。
我们不希望用户执行此迁移,因此此迁移是可选的。虽然原生使用 Cloud Firestore 有明显的优势,例如客户端身份验证、Firebase 规则集成,当然还有 Firebase 实时数据库,但迁移步骤“不太方便”:
- 您必须使用与当前应用项目不同的项目。
- 如果应用已添加 Datastore 实体,则相应项目无法切换到原生模式 Firestore
- 同样,选择了原生模式 Firestore 的项目也无法恢复为 Datastore 模式 Firestore。
- 没有可将数据从一个项目流式传输到另一个项目的迁移工具。
- Firestore 不支持某些关键 Datastore 功能,包括命名空间和更高的写入吞吐量(>1 万次/秒)。
- 导出和导入工具属于“原始”工具,并且只能“全盘导出/导入”。
- 如果您的应用包含许多 Datastore 实体,则导出并导入到 Firestore 可能需要花费数小时。
- 在此期间,您的应用/服务将无法写入/更新数据。
- 迁移活动计入正常使用量;您可能需要将其分散到多个时间段(尽可能分散到每日配额中),以最大限度地降低费用。
- 由于新服务在不同的项目中运行,因此您需要等待 DNS 更新传播。
- Datastore 和 Firestore 的数据模型相似但不同,因此迁移需要更新应用/服务的工作方式
- Datastore 中的祖先查询现在是 Firestore 集合查询(默认)
- Datastore 中的广泛类型查询是 Firestore 合集组查询
- 索引和处理方式不同,等等。
不过,如果您有一个相当简单的应用需要考虑迁移,或者您正准备模拟此类迁移,或者您只是想了解 Datastore 与 Firestore 之间的区别,那么请继续!
Python 2 用户:此可选的迁移 Codelab 仅以 Python 3 呈现,但由于 Cloud Firestore 也支持 2.x,因此用户可以推断使用方面的差异。例如,Firestore 记录使用 Unicode 字符串(而非字节字符串),因此 Python 2 字符串字面量需要使用 u'' 前导指示符,这意味着 2.x store_visit() 函数将如下所示:
def store_visit(remote_addr, user_agent):
doc_ref = fs_client.collection(u'Visit')
doc_ref.add({
u'timestamp': datetime.now(),
u'visitor': u'{}: {}'.format(remote_addr, user_agent),
})
除此之外,客户端库应以类似方式运行。需要考虑的唯一其他问题是,2.x Cloud Firestore 库在开发方面处于“冻结”状态,因此越来越多的新功能将仅在 3.x Firestore 客户端库中提供。
继续执行此迁移,本教程的主要步骤如下:
- 设置/准备工作
- 添加 Cloud Firestore 库
- 更新应用文件
3. 设置/准备工作
在开始学习本教程的主要部分之前,让我们设置项目、获取代码,然后部署基准应用,以便我们知道我们从工作代码开始。
1.设置项目
我们建议您重复使用与完成模块 3 Codelab 相同的项目。或者,您可以创建一个全新的项目或重复使用另一个现有项目。确保该项目具有有效的结算账号,并且已启用 App Engine(应用)。
2. 获取基准示例应用
此 Codelab 的先决条件之一是拥有一个工作正常的模块 3 示例应用。如果您没有,请先完成模块 3 教程(上面的链接),然后再继续学习。或者,如果您已经熟悉其内容,可以直接从下面的模块 3 开始。
无论您是使用自己的代码还是我们的代码,我们都能在模块 3 中。本模块 6 Codelab 将会逐步引导您完成每个步骤,完成之后,它应该类似于 FINISH 点的代码。(本教程仅适用于 Python 3。)
模块 3 文件(您或我们的文件)的目录应如下所示:
$ ls
README.md main.py templates
app.yaml requirements.txt
3. (重新)部署模块 3 应用
您现在需要执行的剩余预处理步骤:
- 熟悉
gcloud命令行工具(必要的话) - (重新)将模块 3 代码部署到 App Engine(必要的话)
当您成功执行这些步骤并确认操作有效后,我们将在本教程中进行本教程,从配置文件开始。
Python 2 要求
- 确保
app.yaml(仍然)引用第三方捆绑软件包:grpcio和setuptools。 - 确保
appengine_config.py仍使用pkg_resources和google.appengine.ext.vendor将应用指向第三方资源。 - 在下一部分(更新
requirements.txt)中,您必须使用google-cloud-firestore==1.9.0,因为这是与 2.x 兼容的 Python Firestore 客户端库的最终版本。- 如果您的
requirements.txt中有google-cloud-core的条目,请保持原样。 - 删除
lib并使用pip install -t lib -r requirements.txt重新安装。
- 如果您的
4. 更新配置文件(添加 Cloud Firestore 库)
除了设置之外,接下来还需要更新配置,然后更新应用文件。对于前者,唯一的配置更改是 requirements.txt 文件中的小幅软件包交换,因此我们现在就来完成这项操作。
将 requirements.txt 中的 google-cloud-datastore 行替换为 google-cloud-firestore,使其看起来如下所示:
Flask==1.1.2
google-cloud-firestore==2.0.2
我们建议使用每个库的最新版本;上述版本号是撰写本文时的最新版本。FINISH 代码库文件夹中的代码更新频率更高,可能包含较新版本。
没有其他配置更改,因此 app.yaml 和 templates/index.html 保持不变。
5. 更新应用文件
只有一个应用文件 main.py,因此本部分中的所有更改都只会影响该文件。
1. 导入
切换软件包导入是一项小变更,从 datastore 更改为 firestore:
- 之前:
from google.cloud import datastore
- 之后:
from google.cloud import firestore
2. Firestore 访问权限
初始化 Flask 后,创建 Firestore 客户端。进行与上述类似的更改,但针对的是客户端初始化:
- 之前:
app = Flask(__name__)
ds_client = datastore.Client()
- 之后:
app = Flask(__name__)
fs_client = firestore.Client()
通过从 Cloud NDB 迁移到 Cloud Datastore,您已经完成了迁移到 Cloud Firestore 的大部分工作。借助 Datastore,您可以创建数据记录(以由通用属性组成的实体形式),并按键对其进行分组。Firestore 中的数据记录是文档,由键值对组成,并分组到集合中。从 Datastore 迁移时,您需要考虑这些差异,因为它们会在您创建数据记录以及查询数据记录时体现出来。结果可能会因数据存储区代码的复杂程度而异。
对于 Datastore,您可以根据实体类型以及过滤和排序条件进行查询。对于 Firestore,查询数据的方式类似。我们来看一个简单的示例,假设有以下查询值、客户端(分别为 ds_client 或 fs_client)和导入:
from datetime import datetime
from firestore.Query import DESCENDING
OCT1 = datetime(2020, 10, 1)
LIMIT = 10
对于 Datastore,我们来查询 2020 年 10 月 1 日之后最新的 10 个 Visit 实体,并按降序排列:
query = ds_client.query(kind='Visit')
query.add_filter('timestamp', '>=', datetime(2020, 10, 1))
query.order = ['-timestamp']
return query.fetch(limit=LIMIT)
对 Firestore 执行相同的操作,从 Visit 集合开始:
query = fs_client.collection('Visit')
query.where('timestamp', '>=', datetime(2020, 10, 1))
query.order_by('timestamp', direction=DESCENDING)
return query.limit(LIMIT).stream()
示例应用查询更简单(没有“WHERE”子句)。回顾一下,以下是 Cloud Datastore 代码:
- 之前:
def store_visit(remote_addr, user_agent):
entity = datastore.Entity(key=ds_client.key('Visit'))
entity.update({
'timestamp': datetime.now(),
'visitor': '{}: {}'.format(remote_addr, user_agent),
})
ds_client.put(entity)
def fetch_visits(limit):
query = ds_client.query(kind='Visit')
query.order = ['-timestamp']
return query.fetch(limit=limit)
迁移到 Firestore 后,您会发现创建新文档与创建实体类似,查询也与之前所示的相同。
- 之后:
def store_visit(remote_addr, user_agent):
doc_ref = fs_client.collection('Visit')
doc_ref.add({
'timestamp': datetime.now(),
'visitor': '{}: {}'.format(remote_addr, user_agent),
})
def fetch_visits(limit):
visits_ref = fs_client.collection('Visit')
visits = (v.to_dict() for v in visits_ref.order_by('timestamp',
direction=firestore.Query.DESCENDING).limit(limit).stream())
return visits
主函数 root() 和 index.html 模板文件保持不变。仔细检查您的更改,然后保存、部署并验证。
6. 总结/清理
部署应用
使用 gcloud app deploy 重新部署应用,并确认应用可正常运行。您的代码现在应与模块 6 代码库中的内容相匹配(如果您偏好 2.x 版本,则应与该版本相匹配)。
如果您跳过本系列,但未执行任何上述 Codelab,则应用本身不会更改;它会记录对主网页 (/) 的所有访问,在您访问过该网站后,将如下所示:

恭喜您完成本可选模块 6 的迁移。就 App Engine 数据存储而言,这可能是您能进行的最后一次迁移(如果不是,也是最后几次迁移之一)。如果您尚未将应用容器化,可以考虑将应用容器化以迁移到 Cloud Run(请参阅模块 4 和 5,Codelab 链接如下)。
可选:清理
何不准备好清理,以避免在进入下一个迁移 Codelab 时继续计费?作为现有开发者,您可能已经了解 App Engine 的价格信息。
可选:停用应用
如果您尚未准备好学习下一个教程,请停用应用,以免产生费用。准备好继续学习下一个 Codelab 后,您可以重新启用该功能。应用被停用后,不会产生任何流量产生费用,但如果超出免费配额,您可能还需要为 Firestore 使用量付费,因此请删除足够的数据,使用量低于该上限。
另一方面,如果您不打算继续进行迁移,并希望完全删除所有内容,可以关闭项目。
后续步骤
除了本教程之外,您还可以考虑其他几个迁移模块 Codelab:
- 模块 7:App Engine 推送任务队列(如果您使用 [推送] 任务队列,此为必需参数)
- 向模块 1 应用添加了 App Engine
taskqueue推送任务 - 为用户在第 8 模块中迁移到 Cloud Tasks 做准备
- 向模块 1 应用添加了 App Engine
- 模块 4:使用 Docker 迁移到 Cloud Run
- 使用 Docker 将应用容器化,以便在 Cloud Run 上运行
- 通过此迁移,您可以继续使用 Python 2。
- 模块 5:使用 Cloud Buildpack 迁移到 Cloud Run
- 使用 Cloud Buildpacks 将应用容器化,以便在 Cloud Run 上运行
- 您无需了解 Docker、容器或
Dockerfile。 - 要求您的应用已迁移到 Python 3(buildpack 不支持 Python 2)
7. 其他资源
App Engine 迁移模块 Codelab 问题/反馈
如果您发现本 Codelab 存在任何问题,请先搜索您的问题,然后再提交。用于搜索和创建新问题的链接:
迁移时可参考的资源
下表中提供了指向模块 3(开始)和模块 6(完成)的 Repo 文件夹的链接。您还可以从所有 App Engine 迁移的代码库中访问这些示例,您可以克隆该代码库或下载 ZIP 文件。
Codelab | Python 2 | Python 3 |
(代码) | ||
模块 6 | (不适用) |
App Engine 资源
以下是有关此特定迁移的其他资源:
- Python Cloud Datastore 和 Cloud Firestore 参考文档
- 迁移到 Python 3 和 GAE 新一代运行时
- 常规