1. 概览
本系列 Codelab(自定进度的实操教程)旨在指导 Google App Engine(标准版)开发者完成一系列迁移,从而对应用进行现代化改造。大多数此类迁移涉及从原始的运行时捆绑服务移除,因为新一代运行时更加灵活,并为用户提供了更多服务选项。对应用进行现代化改造的另一种方式包括升级到较新的产品,这也是此 Codelab 的主题。
使用 Cloud NDB 或 Cloud Datastore 客户端库访问 Datastore 的 App Engine 用户可以随时使用,无需进一步迁移。不过,Cloud Firestore 代表了最新、可扩缩、高可用性的 NoSQL 数据存储区,具有 Firebase 实时数据库的功能。
如果您是开发者,想要使用 Firestore 来利用其功能,或者至少有足够的兴趣来探索迁移的意义,那么您来对地方了。本教程介绍了如何将使用 Cloud Datastore 的 App Engine 应用迁移到 Cloud Firestore。
您将了解如何
- 识别 Datastore 与 Firestore 之间的差异
- 从 Cloud Datastore 迁移到 Cloud Firestore
所需条件
- 符合以下条件的 Google Cloud Platform 项目:
- 基本 Python 技能
- 常用 Linux 命令的实践知识
- 具备开发和部署 App Engine 应用的基础知识
- 建议您先完成第 3 单元 Codelab,包括将其移植到 Python 3,然后再开始学习本 Codelab(第 6 单元)。
- 有效的 Module 3 Cloud Datastore Python 3 App Engine 应用。
调查问卷
如何使用此 Codelab?
<ph type="x-smartling-placeholder">2. 背景
App Engine 的 Datastore 在 2013 年成为了自己的产品:Google Cloud Datastore,现在可供 App Engine 外部的开发者使用。第二年,Google 收购了 Firebase。当时,它以自己的实时数据库而闻名。
在接下来的几年中,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,并且 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 功能,包括命名空间和更高的写入吞吐量(超过 10k/秒)。
- 导出和导入工具“原初”以及“全部或不提供”场景。
- 如果应用有许多 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 将逐步引导您完成每个步骤,完成后,它应该类似于“完成”处的代码。(本教程仅适用于 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 客户端库的最终 2.x 版本。- 如果您的
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 代码的复杂程度而异。
对于 Datastore,您可以根据实体类型以及过滤和排序条件进行查询。对于 Firestore,查询数据与此类似。我们来看一个简单的示例,假设有以下查询值、客户端(分别为 ds_client
或 fs_client
)和 import:
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)
从 Visit
集合中对 Firestore 执行相同的操作:
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
重新部署您的应用,并确认应用能正常运行。您的代码现在应与 Module 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 单元:迁移到 Cloud Run with Docker
- 使用 Docker 将应用容器化,以便在 Cloud Run 上运行
- 此次迁移让您可以继续使用 Python 2。
- 模块 5:使用 Cloud Buildpack 迁移到 Cloud Run
- 使用 Cloud Buildpack 将应用容器化,以便在 Cloud Run 上运行
- 您无需了解有关 Docker、容器或
Dockerfile
的任何知识。 - 要求您的应用已迁移到 Python 3(Buildpack 不支持 Python 2)
7. 其他资源
App Engine 迁移模块 Codelab 问题/反馈
如果您在此 Codelab 中发现任何问题,请先搜索您的问题,然后再提交。用于搜索和创建新问题的链接:
迁移时可参考的资源
下表列出了模块 3(START)和模块 6 (FINISH) 对应的代码库文件夹的链接。您还可以从所有 App Engine 迁移的代码库访问这些迁移项目,您可以克隆或下载 ZIP 文件。
Codelab | Python 2 | Python 3 |
(代码) | ||
模块 6 | (不适用) |
App Engine 资源
以下是有关此特定迁移的其他资源:
- Python Cloud Datastore 和 Cloud Firestore 引用
- 迁移到 Python 3 和 GAE 下一代运行时
- 常规