使用时间点恢复 (PITR)

本页介绍如何使用时间点恢复 (PITR) 来保留和恢复 Cloud Firestore 中的数据。

如需了解 PITR 概念,请参阅时间点恢复

权限

如需获取管理 PITR 设置所需的权限,请让管理员向您授予您想要启用 PITR 的项目的以下 IAM 角色:

  • Cloud Datastore Owner (roles/datastore.owner)

对于自定义角色,请确保已为其授予以下权限:

  • 如需在创建数据库时启用 PITR:datastore.databases.create
  • 如需更新现有数据库上的 PITR 设置:datastore.databases.updatedatastore.databases.list
  • 如需从 PITR 数据进行读取:datastore.databases.getdatastore.entities.getdatastore.entities.list
  • 如需导出 PITR 数据:datastore.databases.export
  • 如需导入 PITR 数据:datastore.databases.import

准备工作

在开始使用 PITR 之前,请注意以下几点:

  • 启用 PITR 后,您无法立即开始读取过去 7 天内的数据。
  • 如果您要在创建数据库时启用 PITR,必须使用 gcloud firestore databases create 命令。使用 GCP 控制台创建数据库时不支持启用 PITR。
  • 启用 PITR 后,Cloud Firestore 会立即开始保留版本。
  • 停用 PITR 后,您将无法在 PITR 窗口中读取 PITR 数据。
  • 如果您在停用 PITR 后立即将其重启,则过去的 PITR 数据将不再可用。系统将在 PITR 失效日期之后删除停用 PITR 之前创建的任何 PITR 数据。
  • 如果您在过去一小时内不小心删除了数据并停用了 PITR,则可以在删除后的一小时内启用 PITR,从而恢复数据。
  • 对已过期的 PITR 数据执行的任何读取操作都会失败。

启用 PITR

在使用 PITR 之前,请为 Google Cloud 项目启用结算功能。只有启用了结算功能的 Google Cloud 项目才能使用 PITR 功能。

如需为数据库启用 PITR,请执行以下操作:

控制台

  1. 在 Google Cloud Platform 控制台中,进入数据库页面。

    前往“数据库”

  2. 从数据库列表中选择所需的数据库。

  3. 在导航菜单中,点击灾难恢复

  4. 点击修改以修改设置。

  5. 选中启用时间点恢复复选框,然后点击保存

启用 PITR 会产生存储费用。如需了解详情,请参阅价格

如需停用 PITR,请在 GCP 控制台的“灾难恢复”页面中取消选中启用时间点恢复复选框。

gcloud

可以使用 gcloud firestore databases create 命令在创建数据库期间启用 PITR,如下所示:

gcloud firestore databases create\
  --location=LOCATION\
  [--database=DATABASE_ID; default="(default)"]\
  [--type=TYPE; default="firestore-native"]\
  --enable-pitr

替换各值,如下所示:

  • Location - 要在其中创建数据库的位置。
  • DATABASE_ID - 设置为数据库 ID 或(使用默认值)。
  • TYPE - 设置为 firestore-native。

您可以使用 gcloud firestore databases update 命令停用 PITR,如下所示:

gcloud firestore databases update\
  [--database=DATABASE_ID; default="(default)"]\
  --no-enable-pitr

替换各值,如下所示:

  • DATABASE_ID - 设置为数据库 ID 或(使用默认值)。

获取保留期限和最早版本时间

控制台

  1. 在 Google Cloud Platform 控制台中,进入数据库页面。

    前往“数据库”

  2. 从数据库列表中选择所需的数据库。

  3. 在导航菜单中,点击灾难恢复

  4. 设置部分中,注意保留期限最早版本时间

    • 保留期限:Cloud Firestore 为数据库保留所有数据版本的时长。如果停用了 PITR,该值为 1 小时;如果启用了 PITR,该值为 7 天。
    • 最早版本时间:可在 PITR 窗口中读取旧版数据的最早时间戳。该值会由 Cloud Firestore 不断更新,并且会在查询时过时。如果您使用该值恢复数据,请确保计算从发出查询到查询恢复那一刻这段时间。
    • 时间点恢复:如果启用了 PITR,则显示 Enabled。如果停用了 PITR,您会看到 Disabled

gcloud

运行 gcloud firestore databases describe 命令,如下所示:

gcloud firestore databases describe --database=DATABASE_ID

DATABASE_ID 替换为数据库 ID 或 default

输出如下:

    appEngineIntegrationMode: ENABLED
    concurrencyMode: PESSIMISTIC
    createTime: '2021-03-24T17:02:35.234Z'
    deleteProtectionState: DELETE_PROTECTION_DISABLED
    earliestVersionTime: '2023-06-12T16:17:25.222474Z'
    etag: IIDayqOevv8CMNTvyNK4uv8C
    keyPrefix: s
    locationId: nam5
    name: projects/PROJECT_ID/databases/(default)
    pointInTimeRecoveryEnablement: POINT_IN_TIME_RECOVERY_DISABLED
    type: FIRESTORE_NATIVE
    uid: 5230c382-dcd2-468f-8cb3-2a1acfde2b32
    updateTime: '2021-11-17T17:48:22.171180Z'
    versionRetentionPeriod: 3600s

其中

  • earliestVersionTime - 最早存储的 PITR 数据的时间戳。
  • pointInTimeRecoveryEnablement:如果启用了 PITR,则显示 POINT_IN_TIME_RECOVERY_ENABLED。如果停用了 PITR,您会看到 POINT_IN_TIME_RECOVERY_DISABLED,或者 pointInTimeRecoveryEnablement 字段可能不会显示。
  • versionRetentionPeriod - 保留 PITR 数据的时间段(以毫秒为单位)。如果停用 PITR,该值可能是 1 小时;如果启用了 PITR,则可能是 7 天。

读取 PITR 数据

您可以使用客户端库、REST API 方法或 FirestoreIO Apache Beam 连接器读取 PITR 数据。

客户端库

Java

您必须使用 ReadOnly 事务来读取 PITR 数据。您不能在读取操作中直接指定 readTime。如需了解详情,请参阅事务和批量写入

  Firestore firestore = …

  TransactionOptions options =
          TransactionOptions.createReadOnlyOptionsBuilder()
              .setReadTime(
                  com.google.protobuf.Timestamp.newBuilder()
                      .setSeconds(1684098540L)
                      .setNanos(0))
              .build();

  ApiFuture<Void> futureTransaction = firestore.runTransaction(
              transaction -> {
                // Does a snapshot read document lookup
                final DocumentSnapshot documentResult =
                    transaction.get(documentReference).get();

                // Executes a snapshot read query
                final QuerySnapshot queryResult =
                  transaction.get(query).get();
              },
              options);

  // Blocks on transaction to complete
  futureTransaction.get();

节点

您必须使用 ReadOnly 事务来读取 PITR 数据。您不能在读取操作中直接指定 readTime。如需了解详情,请参阅事务和批量写入

  const documentSnapshot = await firestore.runTransaction(
    updateFunction => updateFunction.get(documentRef),
    {readOnly: true, readTime: new Firestore.Timestamp(1684098540, 0)}
);

  const querySnapshot = await firestore.runTransaction(
    updateFunction => updateFunction.get(query),
    {readOnly: true, readTime: new Firestore.Timestamp(1684098540, 0)}
  )

REST API

所有 Cloud Firestore 读取方法都支持 PITR 读取,这些读取方法包括: getlistbatchGetlistCollectionIdslistDocumentsrunQueryrunAggregationQuerypartitionQuery

如需使用 REST 方法执行读取操作,请尝试以下方法之一:

  1. 在读取方法请求中,将 readTime 值作为支持的 PITR 时间戳传递给 readOptions 方法。PITR 时间戳可以是过去一小时内的微秒精度时间戳,也可以是过去一小时之前的完整一分钟时间戳,但不得早于 earliestVersionTime

  2. readTime 参数与 BeginTransaction 方法一起使用,作为 ReadOnly 事务的一部分以用于多次 PITR 读取。

Apache Beam

使用 Cloud FirestoreIO Apache Beam 连接器可以通过 Dataflow 大规模读取或写入 Cloud Firestore 数据库中的文档。

Cloud FirestoreIO 连接器的以下读取方法支持 PITR 读取。这些读取方法支持可用于 PITR 读取的 withReadTime(@Nullable Instant readTime) 方法:

Java

以下代码可以与示例 Dataflow 流水线代码搭配使用,以执行批量读取或写入操作。该示例使用 withReadTime(@Nullable Instant readTime) 方法进行 PITR 读取。

  Instant readTime = Instant.ofEpochSecond(1684098540L);

  PCollection<Document> documents =
      pipeline
          .apply(Create.of(collectionId))
          .apply(
              new FilterDocumentsQuery(
                  firestoreOptions.getProjectId(), firestoreOptions.getDatabaseId()))
          .apply(FirestoreIO.v1().read().runQuery().withReadTime(readTime).withRpcQosOptions(rpcQosOptions).build())
  ...

如需查看 Dataflow 流水线中 readTime 示例的完整列表,请参阅 GitHub 代码库

从 PITR 数据导出和导入

您可以使用 gcloud firestore export 命令将数据库从 PITR 数据导出到 Cloud Storage。您可以导出 PITR 数据,其中时间戳为过去七天内的整分钟时间戳,但不早于 earliestVersionTime。如果指定的时间戳已不存在数据,导出操作将失败。

PITR 导出操作支持所有过滤条件,包括导出所有文档和导出特定集合。

  1. 导出数据库,将 snapshot-time 参数指定为所需恢复时间戳。

    gcloud

    运行以下命令,将数据库导出到存储桶。

    gcloud firestore export gs://[BUCKET_NAME_PATH] \
        --snapshot-time=[PITR_TIMESTAMP] \
        --collection-ids=[COLLECTION_IDS] \
        --namespace-ids=[NAMESPACE_IDS]
    

    其中:

    • BUCKET_NAME_PATH - 有效的 Cloud Storage 存储桶(包含可选路径前缀),用于存储导出文件。
    • PITR_TIMESTAMP - 分钟粒度的 PITR 时间戳,例如 2023-05-26T10:20:00.00Z2023-10-19T10:30:00.00-07:00
    • COLLECTION_IDS - 集合 ID 或集合组 ID 的列表,例如 'specific collection group1','specific collection group2'
    • NAMESPACE_IDS - 命名空间 ID 的列表,例如 'customer''orders'

    在导出 PITR 数据之前,请注意以下几点:

    • RFC 3339 格式指定时间戳。例如 2023-05-26T10:20:00.00Z2023-10-19T10:30:00.00-07:00
    • 请确保您指定的时间戳是过去七天内的整分钟时间戳,但不早于 earliestVersionTime。如果指定的时间戳已不存在数据,则会生成错误。 时间戳必须是整分钟,即使指定的时间在过去一小时内也是如此。
    • 您无需为失败的 PITR 导出付费。
  2. 导入到数据库。

    按照导入所有文档中的步骤导入您导出的数据库。如果数据库中已有任何文档,这类文档将会被覆盖。