写入
本页面列出了您可以发送到 Bigtable 的写入请求类型,并介绍了何时应使用这些请求以及何时不应使用。如需了解如何在写入时汇总单元格中的数据,请参阅在写入时汇总值。
借助 Bigtable Data API 和客户端库,您可以以编程方式将数据写入表格。Bigtable 会针对每次写入发回响应或确认。
每个客户端库都具备发送以下类型的写入请求的功能:
- 简单写入
- 增量和附加
- 条件写入
- 批量写入
Bigtable 客户端库具备适用于简单写入和批量写入的内置智能重试功能,这意味着其可以无缝处理暂时无法使用的情况。例如,如果您的应用尝试写入数据却遇到临时中断或网络问题,它会自动重试,直至提交写入或达到请求时限。这种弹性同时支持采用单集群路由或多集群路由的单集群和复制的实例。
对于批量写入和流式写入操作,您可以使用 Bigtable Beam 连接器。如需了解详情,请参阅批量写入。
如需了解适用于写入请求的限制,请参阅配额和限制。
如需查看本页所述写入请求的 Cloud Bigtable 客户端库示例,请参阅写入示例。
写入的类型和适用情形
所有写入请求都包含以下基本组成部分:
- 要写入的表的名称。
- 向 Bigtable 说明如何进行流量路由的应用配置文件 ID。
- 一个或多个突变。变更包含以下元素:
- 列族名称
- 列限定符
- 时间戳
- 要写入表的值
变更的时间戳以当前日期和时间作为默认值,时间是从 Unix 纪元(世界协调时间 [UTC] 1970 年 1 月 1 日 00:00:00)起经过的时间。
您发送给 Bigtable 的时间戳必须是微秒值,精确率最高为毫秒级。微秒级精确率(例如 3023483279876543)的时间戳会被拒绝。在此示例中,可接受的时间戳值为 3023483279876000。
单个写入请求中的所有变更都具有相同的时间戳,除非您将其覆盖。您可以将写入请求中所有变更的时间戳设置为彼此相同或不同。
简单写入
您可以使用 MutateRow 请求将单行数据写入 Bigtable,该请求包含表名称、应使用的应用配置文件的 ID、行键以及该行的最多 10 万个变更。单行写入为原子化写入。在对单行进行多项变更时,请使用这种类型的写入。
如需查看演示如何发送简单写入请求的代码示例,请参阅执行简单写入。
何时不应使用简单写入
在以下使用场景中,简单写入不是写入数据的最佳途径:
写入一批具有连续行键的数据。在这种情况下,您应该使用批量写入而非连续的简单写入,因为前者只需单次后端调用即可应用连续批处理。
您需要高吞吐量(每秒行数或每秒字节数),不需要低延迟。在这种情况下,批量写入速度更快。
增量更新
Bigtable 允许您创建数据类型为汇总的单元格。当您想要更改现有表格单元格中的值时,聚合单元格会进行优化,以便在写入数据时聚合单元格值。以下类型的汇总可供使用:
- 求和 - 递增计数器或保持累计总和。
- 最小值 - 向单元格发送一个整数,Bigtable 会保留这两个值中较小的值。
- 最大值 - 将整数发送到单元格,Bigtable 会保留这两个值中较大的一个。
- HyperLogLog (HLL) - 发送一个添加到单元格中所有值的概率集的值。
用于更新汇总单元格的请求通过 MutateRow 请求发送,并且突变类型为 AddToCell 或 MergeToCell 或其中一种删除突变类型。
附加
如需将数据附加到现有值,您可以使用 ReadModifyWriteRow 请求。此请求包含表名称、应使用的应用配置文件的 ID、行键以及写入数据时要使用的一组规则。每条规则都包含列族名称、列限定符以及附加值或增量。
规则按顺序应用。例如,如果您的请求包含一个请求,用于将包含值 some 的列的值附加到字符串 thing,并且同一请求中的后续规则将同一列附加到 body,则该值会在单个原子写入操作中修改两次,最终值为 somethingbody。后面的规则不会覆盖前面的规则。
您也可以通过 ReadModifyWriteRow 调用来递增整数,但我们建议您改用汇总单元格和 AddToCell 或 MergeToCell。只有当值编码为 64 位大端序有符号整数时,才能使用 ReadModifyWrite 递增该值。Bigtable 会将对空值或不存在的值的增量视为对零值的增量。
ReadModifyWriteRow 请求是原子性的。如果因任何原因而失败,系统都不会重试。
不适用情形 ReadModifyWriteRow
在以下情况下,请勿发送 ReadModifyWriteRow 请求:
您可以通过发送包含
AddToCell突变的MutateRow请求来处理相应的使用情形。如需了解详情,请参阅在写入时聚合值。使用具有多集群路由的应用配置文件。
使用多个单集群应用配置文件并发送写入请求,该请求可能与写入实例中其他集群内的同一行和列的数据冲突。使用单集群路由时,写入请求会发送到单个集群,然后进行复制。
您依赖客户端库提供的智能重试功能。
ReadModifyWriteRow请求无法重试。您正在写入大量数据,并且需要快速完成写入操作。读取然后修改行的请求比简单的写入请求慢。因此,这种写入方式通常不是大规模写入的最佳方法。
例如,如果您想统计数百万个项目(例如网页浏览次数),则应使用
MutateRow和AddToCell突变在写入时更新统计信息。
条件写入
如果要检查行是否符合某条件,然后根据检查结果向该行中写入数据,请提交 CheckAndMutateRow 请求。 这种类型的请求包括行键和行过滤条件。行过滤条件是一组用于检查现有数据值的规则。只有当过滤器检查的特定条件得到满足之后,系统才会将变更提交到行中的特定列。这个先检查后写入的过程作为单个原子化操作完成。
过滤条件请求必须包含以下一种或两种类型的突变:
- 真变更,或过滤返回值时应用的变更。
- 假变更,即过滤未产生任何结果时应用的变更。
在一次写入中,您最多可以提供 100,000 个每种类型的变更(真和假),并且必须至少发送一个。所有变更都完成后,Bigtable 会发送响应。
由于条件写入会读取行来评估过滤条件,因此调用方必须对表拥有 bigtable.tables.readRows 和 bigtable.tables.mutateRows 权限(或对授权视图拥有等效的 bigtable.authorizedViews.readRows 和 bigtable.authorizedViews.mutateRows 权限)。如需了解详情,请参阅访问权限控制。
如需查看演示如何发送条件写入的代码示例,请参阅有条件地写入值。
何时不应使用条件写入
您无法针对以下使用情形使用条件写入:
使用具有多集群路由的应用配置文件。
使用多个单集群应用配置文件并发送写入请求,该请求可能与写入实例中其他集群内的同一行和列的数据冲突。采用单集群路由时,写入请求会发送到单个集群,然后进行复制。
写入大量数据并需要快速完成写入操作。与
ReadModifyWriteRow类似,条件写入请求需要在修改行之前读取行,因此CheckAndModifyRow请求比简单写入请求慢。因此,这种写入方式通常不是大规模写入的最佳方法。
批量写入
您可以使用 MutateRows 请求,通过单个调用写入多个行。MutateRows 请求包含一组多达 10 万个的条目,其中的每个条目均以原子化方式应用。每个条目包含一个行键以及至少一个要应用于该行的变更。一个批量写入请求可包含多达 100,000 个变更,这些变更分布于所有条目之间。例如,批量写入可能包括以下任何排列:
- 100,000 个条目,每个条目中包含 1 项变更。
- 包含 100,000 项变更的 1 个条目。
- 1000 个条目,每个条目中包含 100 项变更。
MutateRows 请求中的每个条目都是原子化条目,但整个请求不是。如有必要,Bigtable 会重试批次中未成功的任何条目,直到所有写入操作都成功或达到请求截止期限。然后,它会返回一个标识批次中各写入操作以及写入操作是否成功的响应。
如需查看演示如何发送批量写入的代码示例,请参阅执行批量写入。
何时不应使用批量写入
将批量数据写入彼此不靠近的行。Bigtable 按行键的字典顺序存储数据,这是字母顺序的二进制版本。因此,当请求中的行键彼此不相似时,Bigtable 会按顺序对其进行处理,而不会采取并行处理方式。吞吐量高,但延迟也高。为避免出现高延迟,当行键相似且 Bigtable 将写入彼此靠近的行时,请使用
MutateRows。针对彼此不靠近的行,请使用MutateRow或简单写入。请求对同一行进行多项变更。在这种情况下,如果在单个简单写入请求中执行所有变更,则效果更佳。这是因为在简单写入中,所有更改都通过单个原子化操作提交,但系统会强制批量写入对同一行的变更进行序列化,从而导致延迟。
批量写入流控制
如果您使用以下任一方式发送批量写入(包括删除),则可以在代码中启用批量写入流控制。
- Bigtable Beam 连接器 (
BigtableIO) - Java 版 Bigtable 客户端库
- Bigtable HBase Beam 连接器 (
CloudBigtableIO) - Java 版 Bigtable HBase 客户端
为 Dataflow 作业启用批量写入流量控制后,Bigtable 会自动执行以下操作:
- 限制流量速率以避免 Bigtable 集群过载
- 确保集群负载足以触发 Bigtable 自动扩缩(如果已启用),从而在需要时自动向集群添加更多节点
这些组合操作可防止集群过载和作业失败,并且您无需在预计运行批量写入之前手动扩缩集群。启用流控制后,集群扩缩会在 Dataflow 作业期间(而不是之前)发生,因此作业完成所需的时间可能比手动扩缩集群更长。
您必须使用针对单集群路由配置的应用配置文件。为目标集群启用 Bigtable 自动扩缩不是必需的,但自动扩缩可让您充分利用批量写入流控制。您可以像使用任何其他作业一样使用 Dataflow 自动扩缩功能。
如需详细了解 Bigtable 自动扩缩,请参阅自动扩缩。如需了解应用配置文件路由政策,请参阅应用配置文件概览。
如需查看代码示例,请参阅启用批量写入流控制。
将数据写入授权视图
如需将数据写入授权视图,您必须使用以下方法之一:
- gcloud CLI
- Java 版 Bigtable 客户端
其他 Bigtable 客户端库尚不支持授权视图访问。
向授权视图写入数据时,除了提供表 ID 之外,还要提供授权视图 ID。
对授权视图的所有写入操作都会直接应用于底层表。
授权视图定义限制
在授权视图中,您可以写入数据的行或列会受到授权视图定义的限制。换句话说,您只能写入满足授权视图指定条件的行和列。
例如,如果授权视图由行键前缀 examplepetstore1 定义,则您无法使用行键 examplepetstore2 写入数据;行键值的开头必须包含整个字符串 examplepetstore1。
同样,如果授权视图由列限定符前缀 order-phone 定义,则您可以使用列限定符 order-phone123 写入数据,但不能使用列限定符 order-tablet。
您的写入请求也不能引用授权视图之外的数据,例如在条件写入请求中检查某个值时。
对于写入或引用授权视图之外的数据的任何请求,系统都会返回 PERMISSION_DENIED 出错提示。
复制
当复制的实例的一个集群收到写入时,该写入会立即复制到该实例中的其他集群。
原子性
您发送到复制的实例的每个 MutateRows 请求都会在请求路由到的集群上作为单个原子操作提交。当写入被复制到实例中的其他集群时,每一个这些集群也会将写入作为原子操作接收。集群不会收到部分变更;变更要么成功,要么对于它修改的所有单元自动失败。
一致性
您写入的数据在多长时间之后可用于读取取决于多个因素,其中包括实例中的集群数量以及应用配置文件使用的路由类型。
对于单集群实例,可以立即读取数据,但如果实例具有多个集群(即使用复制功能),则 Bigtable 是最终一致的。您可以通过将请求路由到同一集群来实现读己所写一致性。
发送写入请求后,您可以创建并使用一致性令牌,并在 StandardReadRemoteWrites 模式下调用 CheckConsistency。用于检查复制一致性的令牌。一般来说,您可以在发送一批写入操作后或在某个时间间隔(例如一小时)后创建一致性令牌。然后,您可以将该令牌交给另一个进程使用,例如发出读取请求的模块,该模块会使用该令牌进行检查,以确保在尝试读取之前所有数据都已复制。
如果您在创建令牌后立即使用该令牌,首次使用时可能需要几分钟时间来检查一致性。此延迟是因为各集群会检查每个其他集群,以确保不再有数据传入。初次使用之后,或者如果您等待几分钟再首次使用令牌,则每次使用令牌时都会立即成功。
冲突解决
Bigtable 表中的每个单元格值都通过四元组(行键、列族、列限定符、时间戳)进行唯一标识。如需详细了解这些标识符,请参阅 Bigtable 存储模型。在极少数情况下,当将两个具有完全相同的四元组的写入发送到两个不同的集群时,Bigtable 会基于服务器端时间使用内部“最后写入内容生效”算法自动解决冲突。Bigtable“最后写入内容生效”实现具有确定性,当副本完成同步后,所有集群都具有四元组的相同值。