创建和管理 protobuf 架构

本文档介绍了如何创建架构软件包以及如何对其执行操作。

在 Bigtable 中,您可以使用 协议缓冲区 (protobuf) 架构查询以字节形式存储在列中的 protobuf 消息中的各个字段。为此,您需要以架构软件包的形式上传架构,架构软件包是一种表级 资源,其中包含一个或多个 protobuf 架构。

使用架构软件包具有以下优势:

  • 节省时间和精力:使用协议缓冲区,您只需在 proto 文件中定义一次数据 结构,然后使用生成的源代码来 写入和读取数据。
  • 提高数据一致性:通过使用 proto 文件作为单一的 事实来源,您可以确保所有应用和服务都使用相同 的数据模型。
  • 消除数据重复:您可以通过在特定项目代码库之外的 proto 文件中定义消息类型,在各个项目中使用协议缓冲区。

在 Bigtable 中使用架构的过程从 proto 文件开始。proto 文件是一种文本文件,用于定义数据的结构。 您可以使用 protobuf 编译器工具(也称为 protoc)来 生成 protobuf 文件描述符集,这是 您的 proto 文件的机器可读架构。然后,您可以使用此描述符集创建架构软件包。

如需查看 proto 文件及其相应描述符集的示例,请参阅示例数据

下图展示了在 Bigtable 中使用架构的过程:

在 Bigtable 中使用 Protobuf 架构的过程。
图 1.在 Bigtable 中使用 protobuf 架构的过程(点击可放大)。

您可以使用 Google Cloud CLI 创建架构软件包。将架构软件包上传到 Bigtable 后,您可以使用 Bigtable Studio 查询构建器、Bigtable 的 GoogleSQL 或 BigQuery 中的 Bigtable 外部表查询数据。

准备工作

如果您计划使用 gcloud CLI,请执行以下步骤:

  1. 安装 Google Cloud CLI
  2. 初始化 gcloud CLI:

    gcloud init
    

所需角色

如需获得创建和管理架构软件包所需的权限,请让管理员向您授予表的 Bigtable 管理员 (roles/bigtable.admin) Identity and Access Management (IAM) 角色。

此预定义角色包含 Bigtable 使用架构软件包所需的权限。如需查看所需的确切权限,请展开所需权限 部分:

所需权限

  • bigtable.schemaBundles.create
  • bigtable.schemaBundles.update
  • bigtable.schemaBundles.delete
  • bigtable.schemaBundles.get
  • bigtable.schemaBundles.list

您也可以使用 自定义角色或其他 预定义角色来获取这些权限。

如需详细了解 Bigtable 角色和权限,请参阅 使用 IAM 进行访问权限控制

生成 protobuf 文件描述符集

您需要先使用 protobuf 编译器工具从 proto 文件生成描述符集,然后才能创建架构软件包。

  1. 如需安装编译器, 请下载软件包并按照 README 文件中的说明操作。
  2. 运行编译器:

    protoc --proto_path=IMPORT_PATH --include_imports \
       --descriptor_set_out=DESCRIPTOR_OUTPUT_LOCATION PATH_TO_PROTO
    

    替换以下内容:

    • IMPORT_PATH:protoc 编译器在其中搜索 proto 文件的目录。
    • DESCRIPTOR_OUTPUT_LOCATION:protoc 编译器在其中保存生成的描述符集的目录。
    • PATH_TO_PROTO:proto 文件的路径。

例如,如需为当前目录中的 library.proto 文件创建名为 library.pb 的描述符集,您可以使用以下命令:

protoc --include_imports --descriptor_set_out=library.pb
library.proto

创建架构软件包

gcloud

如需创建架构软件包,请使用 gcloud bigtable schema-bundles create 命令:

gcloud bigtable schema-bundles create SCHEMA_BUNDLE_ID \
    --instance=INSTANCE_ID \
    --table=TABLE_ID \
    --proto-descriptors-file=PROTO_DESCRIPTORS_FILE

替换以下内容:

  • SCHEMA_BUNDLE_ID:新架构软件包的唯一 ID,不能包含任何英文句点 ('.') 字符。
  • INSTANCE_ID:要在其中创建架构软件包的实例的 ID。
  • TABLE_ID:要在其中创建架构软件包的表的 ID。
  • PROTO_DESCRIPTORS_FILE:在上一步中生成的描述符集的路径。

Java

如需创建架构软件包,请使用 createSchemaBundle 方法:

如需了解如何安装和使用 Bigtable 的客户端库,请参阅 Bigtable 客户端库

如需向 Bigtable 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅 为本地开发环境设置身份验证

try (InputStream in = getClass().getClassLoader().getResourceAsStream(PROTO_FILE_PATH)) {
  if (in == null) {
    throw new FileNotFoundException("Resource not found: " + PROTO_FILE_PATH);
  }
  SchemaBundle schemaBundleObj =
      SchemaBundle.newBuilder()
          .setProtoSchema(
              ProtoSchema.newBuilder().setProtoDescriptors(ByteString.readFrom(in)).build())
          .build();
  CreateSchemaBundleRequest request =
      CreateSchemaBundleRequest.newBuilder()
          .setParent(
              "projects/" + projectId + "/instances/" + instanceId + "/tables/" + tableId)
          .setSchemaBundleId(schemaBundleId)
          .setSchemaBundle(schemaBundleObj)
          .build();
  SchemaBundle schemaBundle = adminClient.createSchemaBundleAsync(request).get();
  System.out.printf("Schema bundle: %s created successfully%n", schemaBundle.getName());
} catch (Exception e) {
  System.err.println("Failed to create a schema bundle: " + e.getMessage());
}

查看有关架构软件包的信息

您需要先拥有至少包含一个架构软件包的 Bigtable 表,然后才能查看有关架构软件包的信息。您可以通过检索单个架构软件包的定义或列出表中的所有架构软件包,获取有关表中架构软件包的信息。

获取架构软件包定义

gcloud

如需获取有关架构软件包的详细信息,请使用 gcloud bigtable schema-bundles describe 命令:

gcloud bigtable schema-bundles describe SCHEMA_BUNDLE_ID \
    --instance=INSTANCE_ID \
    --table=TABLE_ID

替换以下内容:

  • SCHEMA_BUNDLE_ID:架构软件包的 ID。
  • INSTANCE_ID:实例的 ID。
  • TABLE_ID:表的 ID。

Java

如需获取架构软件包的定义,请使用 getSchemaBundle 方法。 此方法会返回包含架构定义的 SchemaBundle 对象。

以下示例展示了如何获取架构软件包并将描述符集反序列化以输出架构的内容:

如需了解如何安装和使用 Bigtable 的客户端库,请参阅 Bigtable 客户端库

如需向 Bigtable 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅 为本地开发环境设置身份验证

SchemaBundle schemaBundle = null;
try {
  schemaBundle =
      adminClient.getSchemaBundle(
          "projects/"
              + projectId
              + "/instances/"
              + instanceId
              + "/tables/"
              + tableId
              + "/schemaBundles/"
              + schemaBundleId);
  // Deserialize and print the FileDescriptorSet
  DescriptorProtos.FileDescriptorSet fileDescriptorSet =
      DescriptorProtos.FileDescriptorSet.parseFrom(
          schemaBundle.getProtoSchema().getProtoDescriptors());

  System.out.println("--------- Deserialized FileDescriptorSet ---------");
  for (DescriptorProtos.FileDescriptorProto fileDescriptorProto :
      fileDescriptorSet.getFileList()) {
    System.out.println("File: " + fileDescriptorProto.getName());
    System.out.println("  Package: " + fileDescriptorProto.getPackage());
    for (DescriptorProtos.DescriptorProto messageType :
        fileDescriptorProto.getMessageTypeList()) {
      System.out.println("  Message: " + messageType.getName());
    }
  }
  System.out.println("--------------------------------------------------");
} catch (InvalidProtocolBufferException e) {
  System.err.println("Failed to parse FileDescriptorSet: " + e.getMessage());
} catch (NotFoundException e) {
  System.err.println(
      "Failed to retrieve metadata from a non-existent schema bundle: " + e.getMessage());
}

输出类似于以下内容:

--------- Deserialized FileDescriptorSet ---------
File: my_schema.proto
Package: my_package
Message: MyMessage
--------------------------------------------------

列出表中的架构软件包

gcloud

如需查看表的架构软件包列表,请使用 gcloud bigtable schema-bundles list 命令:

gcloud bigtable schema-bundles list \
    --instance=INSTANCE_ID \
    --table=TABLE_ID

替换以下内容:

  • INSTANCE_ID:实例的 ID。
  • TABLE_ID:表的 ID。

Java

如需查看表中所有架构软件包的列表,请使用 listSchemaBundles 方法。此方法会返回架构软件包 ID 的列表。

以下示例展示了如何列出表中的架构软件包:

如需了解如何安装和使用 Bigtable 的客户端库,请参阅 Bigtable 客户端库

如需向 Bigtable 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅 为本地开发环境设置身份验证

List<String> schemaBundleIds = new ArrayList<>();
try {
  ListSchemaBundlesRequest request =
      ListSchemaBundlesRequest.newBuilder()
          .setParent(
              "projects/" + projectId + "/instances/" + instanceId + "/tables/" + tableId)
          .build();
  for (SchemaBundle bundle : adminClient.listSchemaBundles(request).iterateAll()) {
    String id = SchemaBundleName.parse(bundle.getName()).getSchemaBundle();
    System.out.println(id);
    schemaBundleIds.add(id);
  }
} catch (NotFoundException e) {
  System.err.println(
      "Failed to list schema bundles from a non-existent table: " + e.getMessage());
}

输出类似于以下内容:

my-schema-bundle-1
my-schema-bundle-2

更新架构软件包

更新架构软件包时,Bigtable 会检查新的描述符集是否与现有描述符集向后兼容。如果不兼容,更新会失败并显示 FailedPrecondition 错误。我们建议您保留已删除的字段编号,以防止重复使用。如需了解详情,请参阅 protobuf 文档中的 Proto 最佳实践

如果您确定不兼容的更改是安全的,并且想要强制更新,则可以使用带有 gcloud CLI 的 --ignore-warnings 标志。

gcloud

如需更新架构软件包以使用其他描述符集,请使用 gcloud bigtable schema-bundles update 命令:

gcloud bigtable schema-bundles update SCHEMA_BUNDLE_ID \
    --instance=INSTANCE_ID \
    --table=TABLE_ID \
    --proto-descriptors-file=PROTO_DESCRIPTORS_FILE

替换以下内容:

  • SCHEMA_BUNDLE_ID:要更新的架构软件包的 ID。
  • INSTANCE_ID:包含架构软件包的实例的 ID。
  • TABLE_ID:包含架构软件包的表的 ID。
  • PROTO_DESCRIPTORS_FILE:新描述符集文件的路径。

可选:如需强制更新(即使存在不兼容的更改),请在命令后附加 --ignore-warnings 标志。如果连续物化视图或逻辑视图使用了架构软件包,则不得强制进行不兼容的更改。

Java

如需了解如何安装和使用 Bigtable 的客户端库,请参阅 Bigtable 客户端库

如需向 Bigtable 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅 为本地开发环境设置身份验证

try (InputStream in = getClass().getClassLoader().getResourceAsStream(PROTO_FILE_PATH)) {
  if (in == null) {
    throw new FileNotFoundException("Resource not found: " + PROTO_FILE_PATH);
  }
  SchemaBundle schemaBundleObj =
      SchemaBundle.newBuilder()
          .setName(
              "projects/"
                  + projectId
                  + "/instances/"
                  + instanceId
                  + "/tables/"
                  + tableId
                  + "/schemaBundles/"
                  + schemaBundleId)
          .setProtoSchema(
              ProtoSchema.newBuilder().setProtoDescriptors(ByteString.readFrom(in)).build())
          .build();
  UpdateSchemaBundleRequest request =
      UpdateSchemaBundleRequest.newBuilder()
          .setSchemaBundle(schemaBundleObj)
          .setUpdateMask(FieldMask.newBuilder().addPaths("proto_schema").build())
          .build();
  SchemaBundle schemaBundle = adminClient.updateSchemaBundleAsync(request).get();
  System.out.printf("Schema bundle: %s updated successfully%n", schemaBundle.getName());
} catch (Exception e) {
  System.err.println("Failed to modify schema bundle: " + e.getMessage());
}

删除架构软件包

gcloud

如需删除架构软件包,请使用 gcloud bigtable schema-bundles delete 命令:

gcloud bigtable schema-bundles delete SCHEMA_BUNDLE_ID \
    --instance=INSTANCE_ID \
    --table=TABLE_ID

替换以下内容:

  • SCHEMA_BUNDLE_ID:要删除的架构软件包的 ID。
  • INSTANCE_ID:包含架构软件包的实例的 ID。
  • TABLE_ID:包含架构软件包的表的 ID。

如果连续物化视图或逻辑视图使用了架构软件包,则不要删除该软件包。

Java

如需了解如何安装和使用 Bigtable 的客户端库,请参阅 Bigtable 客户端库

如需向 Bigtable 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅 为本地开发环境设置身份验证

try {
  adminClient.deleteSchemaBundle(
      "projects/"
          + projectId
          + "/instances/"
          + instanceId
          + "/tables/"
          + tableId
          + "/schemaBundles/"
          + schemaBundleId);
  System.out.printf("SchemaBundle: %s deleted successfully%n", schemaBundleId);
} catch (NotFoundException e) {
  System.err.println("Failed to delete a non-existent schema bundle: " + e.getMessage());
}

限制

架构软件包具有以下限制:

后续步骤