创建和管理 protobuf 架构

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

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

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

  • 节省时间和精力:使用 Protocol Buffer,您只需在 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 Admin (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);
  CreateSchemaBundleRequest request =
      CreateSchemaBundleRequest.of(tableId, schemaBundleId)
          .setProtoSchema(ByteString.readFrom(in));
  SchemaBundle schemaBundle = adminClient.createSchemaBundle(request);
  System.out.printf("Schema bundle: %s created successfully%n", schemaBundle.getId());
} catch (NotFoundException e) {
  System.err.println(
      "Failed to create a schema bundle from a non-existent table: " + e.getMessage());
} catch (IOException e) {
  throw new RuntimeException(e);
}

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

您需要先拥有至少一个架构包的 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(tableId, schemaBundleId);
  // Deserialize and print the FileDescriptorSet
  DescriptorProtos.FileDescriptorSet fileDescriptorSet =
      DescriptorProtos.FileDescriptorSet.parseFrom(schemaBundle.getProtoSchema());

  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 {
  schemaBundleIds = adminClient.listSchemaBundles(tableId);
  for (String schemaBundleId : schemaBundleIds) {
    System.out.println(schemaBundleId);
  }
} 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);
  UpdateSchemaBundleRequest request =
      UpdateSchemaBundleRequest.of(tableId, schemaBundleId)
          .setProtoSchema(ByteString.readFrom(in));
  SchemaBundle schemaBundle = adminClient.updateSchemaBundle(request);
  System.out.printf("Schema bundle: %s updated successfully%n", schemaBundle.getId());
} catch (NotFoundException e) {
  System.err.println("Failed to modify a non-existent schema bundle: " + e.getMessage());
} catch (IOException e) {
  throw new RuntimeException(e);
}

删除架构包

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(tableId, 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());
}

限制

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

  • 每个表最多可以创建 10 个架构包。
  • 架构软件包中序列化的协议缓冲区描述符的总大小不能超过 4 MB。只要软件包的总大小不超过此限制,您可以在软件包中包含的各个架构的数量就没有直接限制。

后续步骤