适用于 DynamoDB 用户的 Bigtable
本文档适用于希望迁移或设计应用以便将其用作 Bigtable 作为数据存储区的 DynamoDB 开发者和数据库管理员。在阅读本文档之前,请先阅读 Bigtable 概览。
Bigtable 和 DynamoDB 是分布式键值对存储,可以支持每秒数百万次查询 (QPS),提供的存储空间可以扩容到 PB 级的数据,并且能够容忍节点故障。
虽然这些数据库服务的功能集类似,但它们的底层架构和交互详情在哪些方面有所不同,您在开始迁移之前必须了解一些重要事项。本文档重点介绍了这两个数据库系统之间的相似之处和不同之处。
控制平面
在 DynamoDB 和 Bigtable 中,您可以通过控制平面配置容量以及设置和管理资源。DynamoDB 是一款无服务器产品,与 DynamoDB 的最高交互级别是表级别。在预配容量模式下,您可以在此预配读取和写入请求单元、选择区域和复制功能,以及管理备份。Bigtable 不是无服务器产品;您必须创建包含一个或多个集群的实例,集群容量由这些集群具有的节点数决定。如需详细了解这些资源,请参阅实例、集群和节点。
下表比较了 DynamoDB 和 Bigtable 的控制平面资源。
DynamoDB | Bigtable |
---|---|
表 :具有已定义主键的项集合。这些表包含备份、复制和容量设置。 | 实例:位于不同 Google Cloud 区域或区域中的一组 Bigtable 集群,这些集群之间会发生复制和连接路由。复制政策在实例级层设置。 集群:同一地理位置 Google Cloud 可用区中的一组节点,出于延迟和复制原因,最好与应用服务器共置。容量通过调整每个集群中的节点数量进行管理。 表:按行键编入索引的值的逻辑组织。 备份在表级层进行控制。 |
读取容量单位 (RCU) 和写入容量单位 (WCU)
:采用固定载荷大小时,允许每秒读取或写入的单位。对于载荷较大的每项操作,您都需要为读取或写入单元付费。UpdateItem 操作会在更新之前或之后,占用所更新项的最大大小所使用的写入容量,即使更新涉及项的部分属性也是如此。 |
节点:负责读取和写入数据的虚拟计算资源。集群包含的节点数量会转化为读取、写入和扫描的吞吐量限制。您可以根据延迟时间目标、请求数和载荷大小的组合来调整节点数量。 SSD 节点在读取和写入操作方面提供相同的吞吐量,这与 RCU 和 WCU 之间的显著差异不同。如需了解详情,请参阅典型工作负载下的性能。 |
分区 :由与节点共置的固态硬盘 (SSD) 支持的连续行块。 每个分区的硬性限制为 1,000 个 WCU、3,000 个 RCU 和 10 GB 数据。 |
平板电脑 :由所选存储媒介(SSD 或 HDD)支持的连续行块。 表会被分成多个片以平衡工作负载。片并非存储在 Bigtable 的节点上,而是存储在 Google 的分布式文件系统中。该系统可以在伸缩时快速地重新分布数据,并通过维护多个副本来提高耐用性。 |
全局表 :一种通过自动将数据更改传播到多个区域来提高数据可用性和耐用性的方法。 | 复制 :一种通过自动将数据更改传播到多个区域或同一区域内的多个可用区来提高数据的可用性和耐用性的方法。 |
不适用 (N/A) | 应用配置文件 :用于指示 Bigtable 如何将客户端 API 调用路由到实例中的相应集群的设置。您还可以将应用配置文件用作标记,对归因指标进行细分。 |
地理位置复制
复制功能用于满足客户对以下方面的要求:
- 在发生可用区级或区域级故障时实现业务连续性的高可用性。
- 无论最终用户身在何处,都可以将您的服务数据放在靠近最终用户的位置,以实现低延迟服务。
- 工作负载隔离时,您需要在一个集群上实现批量工作负载并依赖于复制到服务集群。
Bigtable 支持在最多 8 个提供 Bigtable 的 Google Cloud 区域中可用的可用区中复制集群。大多数区域都有三个可用区。Bigtable 会自动在多主拓扑中跨集群复制数据,这意味着您可以对任何集群执行读写操作。Bigtable 复制具有最终一致性。如需了解详情,请参阅复制概览。
DynamoDB 提供了全局表来支持跨多个区域进行表复制。全局表为多主表,可跨区域自动复制。复制最终保持一致。
下表列出了复制概念,并说明了它们在 DynamoDB 和 Bigtable 中的可用性。
属性 | DynamoDB | Bigtable |
---|---|---|
多主复制 | 可以。 您可以读取和写入任何全局表。 |
可以。 您可以读取和写入任何 Bigtable 集群。 |
一致性模型 | 最终一致。 全局表的区域级读己所写一致性。 |
最终一致。 所有表在区域级别的读己所写数据一致性。 |
复制延迟时间 | 没有服务等级协议 (SLA)。 秒 |
无服务等级协议 (SLA)。 秒 |
配置粒度 | 表级别。 | 实例级。 一个实例可以包含多个表。 |
实现 | 创建一个全局表,其中包含每个选定区域中的表副本。 区域级。 通过将表转换为全局表,跨副本自动复制。 这些表必须启用 DynamoDB 流,并且流中同时包含该项的新图片和旧图片。 删除一个区域即可移除该区域中的全局表。 |
创建具有多个集群的实例。 系统会在该实例中的所有集群之间自动复制。 可用区级。 在 Bigtable 实例中添加和移除集群。 |
复制选项 | 每个表。 | 每个实例。 |
流量路由和可用性 | 流量路由到最近的地理副本。 如果失败,您可以应用自定义业务逻辑来确定何时将请求重定向到其他区域。 |
使用应用配置文件配置集群流量路由政策。 使用多集群路由,将流量自动路由到最近的运行状况良好的集群。 如果发生故障,Bigtable 支持在集群之间进行自动故障切换,以实现高可用性。 |
扩缩 | 复制的写入请求单元 (R-WRU) 中的写入容量会在各副本之间同步。 以复制读取容量单元 (R-RCU) 为单位的读取容量是按副本计算的。 |
您可以根据需要在每个复制集群中添加或移除节点,以独立扩缩集群。 |
费用 | R-WRU 的费用比常规 WRU 高 50%。 | 您需要为每个集群的节点和存储空间付费。 跨可用区进行区域级复制不会产生网络复制费用。 跨区域或跨洲的复制会产生费用。 |
服务等级协议 (SLA) | 99.999% | 99.999% |
数据平面
下表比较了 DynamoDB 和 Bigtable 的数据模型概念。表中的每一行都描述了类似特征。例如,DynamoDB 中的项与 Bigtable 中的行类似。
DynamoDB | Bigtable |
---|---|
项 :一组属性,可通过主键与其他项进行唯一标识。允许的大小上限为 400 KB。 | 行 :由行键标识的单个实体。允许的大小上限为 256 MB。 |
不适用 | 列族:对列进行分组的用户指定命名空间。 |
属性 :名称和值的分组。属性值可以是标量、集或文档类型。属性大小本身没有明确的限制。不过,由于每项内容的大小上限为 400 KB,因此对于只有一个属性的项,该属性最多可有 400 KB 减去属性名称所占大小。 | 列限定符 :列的列族中的唯一标识符。列的完整标识符以 column-family:column-qualifier 表示。列限定符在列族中按字典顺序排序。 列限定符允许的最大大小为 16 KB。 单元格:单元格用于保存给定的行、列和时间戳的数据。单元格包含一个值,大小不得超过 100 MB。 |
主键 :表中项的唯一标识符。它可以是分区键,也可以是复合键。 分区键:由一个属性组成的简单主键。这决定了内容所在的物理分区。文件大小上限为 2 KB。 排序键:用于确定分区中各行排序的键。允许的大小上限为 1 KB。 复合键:由两个属性(分区键和排序键或范围属性)组成的主键。 |
行键 :表格中项的唯一标识符。
通常由值和分隔符的串联表示。
文件大小上限为 4 KB。 列限定符可用于实现与 DynamoDB 的排序键类似的行为。 您可以使用串联的行键和列限定符构建复合键。 如需了解详情,请参阅本文档“架构设计”部分中的架构转换示例。 |
存留时间: 按项的时间戳确定何时不再需要某个项。在指定时间戳的日期和时间之后,该项将从表中删除,且不会消耗任何写入吞吐量。 | 垃圾回收 :每个单元格的时间戳决定了何时不再需要某个项。垃圾回收会在称为压缩的后台进程中删除过期项。垃圾回收政策在列族级别设置,不仅可以根据项的存在时间,还可以根据用户想要维护的版本数来删除项。调整集群大小时,您无需调整压缩容量。 |
运维
借助数据平面操作,您可以对表中的数据执行创建、读取、更新和删除 (CRUD) 操作。下表比较了 DynamoDB 和 Bigtable 的类似数据平面操作。
DynamoDB | Bigtable |
---|---|
CreateTable |
CreateTable |
PutItem BatchWriteItem |
MutateRow MutateRows Bigtable 将写入操作视为更新/插入。 |
UpdateItem
|
Bigtable 将写入操作视为更新/插入。 |
GetItem BatchGetItem 、Query 、Scan |
`ReadRow `` ReadRows `(范围、前缀、反向扫描)Bigtable 支持按行键前缀、正则表达式模式或行键范围前向或后向进行高效扫描。 |
数据类型
Bigtable 和 DynamoDB 都是无架构的。您可以在写入时定义列,而无需对列存在性或数据类型在表范围内强制执行。同样,给定的列或属性数据类型可能因行或项而异。不过,DynamoDB 和 Bigtable API 处理数据类型的方式有所不同。
每个 DynamoDB 写入请求都包含了各个属性的类型定义,该属性会与读取请求的响应一起返回。
Bigtable 将所有内容视为字节,并要求客户端代码知道类型和编码,以便客户端可以正确解析响应。一个例外是增量操作,此类操作会将值解释为 64 位大端序有符号整数。
下表比较了 DynamoDB 和 Bigtable 在数据类型方面的差异。
DynamoDB | Bigtable |
---|---|
标量类型 :在服务器响应中作为数据类型描述符令牌返回。 | 字节 :字节会转换为客户端应用中的预期类型。 Increment 将值解释为 64 位大端序有符号整数 |
集 :唯一元素未排序的集合。 | 列族 :您可以使用列限定符作为集合成员名称,并且对于每个列限定符,都提供一个 0 字节作为单元格值。集成员在其列族中按字典顺序排序。 |
映射 :具有唯一键的未排序的键值对集合。 | 列族 使用列限定符作为值的映射键和单元格值。映射键按字典顺序排序。 |
列表 :经过排序的项集合。 | 列限定符 使用插入时间戳可以实现与 list_append 行为等效的行为,反转插入时间戳来实现前置。 |
架构设计
架构设计的一个重要考虑因素是如何存储数据。Bigtable 和 DynamoDB 之间的主要区别在于,它们在以下方面的处理方式:
- 单个值的更新
- 数据排序
- 数据版本控制
- 大型值的存储
单个值的更新
即使更新涉及项的属性子集,DynamoDB 中的 UpdateItem
操作也会消耗“之前”和“之后”项大小中的较大者的写入容量。这意味着在 DynamoDB 中,您可以将频繁更新的列放在单独的行中,即使它们在逻辑上与其他列同属于同一行也是如此。
无论单元格是某一行中的唯一列还是数千列中的一列,Bigtable 都可以高效地更新单元格。如需了解详情,请参阅简单写入。
数据排序
DynamoDB 哈希并随机分布分区键,而 Bigtable 按行键以字典顺序存储行,并将任何哈希处理工作留给用户。
随机键分布并非适用于所有访问模式的最佳选择。它可以降低热行范围的风险,但会导致涉及跨分区边界的扫描的访问模式成本高昂且效率低下。这些无界限扫描很常见,尤其是对于具有时间维度的用例。
处理这种类型的访问模式(跨分区边界的扫描)需要在 DynamoDB 中使用二级索引,但 Bigtable 可以在不需要二级索引的情况下处理二级索引。 同样,在 DynamoDB 中,查询和扫描操作的扫描数据量上限为 1 MB,因此分页需要超过此限制。Bigtable 没有这种限制。
尽管有随机分布的分区键,但如果所选分区键不能均匀分配流量(会对吞吐量产生不利影响),DynamoDB 仍然可以使用热分区。为解决此问题,DynamoDB 建议使用写入分片,即在多个逻辑分区键值之间随机拆分写入数据。
如需应用此设计模式,您需要从固定集合(例如 1 到 10)中创建一个随机数字,然后将此数字用作逻辑分区键。由于您是随机分配分区键,因此对表的写入会均匀分布在所有分区键值中。
Bigtable 将此过程称为键加盐,它可以有效避免热片。
数据版本控制
每个 Bigtable 单元都有一个时间戳,最近的时间戳始终是任何给定列的默认值。时间戳的一个常见使用场景是进行版本控制,即,将一个新单元格写入一个列中,该列的数据与该行和列的先前版本的数据区分开来(按时间戳)。
DynamoDB 没有这样的概念,并且需要复杂的架构设计来支持版本控制。此方法涉及为每个项创建两个副本:一个副本的版本号前缀为零(如 v0_
),位于排序键开头,另一个副本的版本号前缀为 1(如 v1_
)。每次更新项时,您都会在更新版本的排序键中使用下一个更高版本前缀,并将更新后的内容复制到版本前缀为零的项中。这可确保能够使用零前缀找到任何项的最新版本。此策略不仅需要应用端逻辑进行维护,还会使数据写入变得非常高昂且速度缓慢,因为每次写入都需要读取先前的值再执行两次写入。
多行事务与大行容量
Bigtable 不支持多行事务。不过,由于它可让您存储比 DynamoDB 中的项大得多的行,因此您通常可以通过设计架构将相关项归入共享行键下来获得预期的事务性。如需查看说明此方法的示例,请参阅单表设计模式。
存储大型值
由于一个类似于 Bigtable 行的 DynamoDB 项的大小上限为 400 KB,因此存储大量值需要跨项目拆分值,或将值存储在 S3 等其他媒介中。这两种方法都会增加应用的复杂性。相比之下,Bigtable 单元最多可以存储 100 MB,Bigtable 行最多可以支持 256 MB。
架构转换示例
本部分中的示例将架构从 DynamoDB 转换为 Bigtable,并牢记了关键的架构设计差异。
迁移基本架构
商品清单就是演示基本键值对模式的一个很好的例子。此类架构在 DynamoDB 中可能如下所示。
主键 | 特性 | |||
---|---|---|---|---|
分区键 | 排序键 | 说明 | Price | 缩略图 |
帽子 | 浅顶软呢帽#brandA | 采用优质羊毛制作... | 30 | https://storage… |
帽子 | 浅顶软呢帽#brandB | 经久耐用的防水帆布... | 28 | https://storage… |
帽子 | 新闻小孩#brandB | 为您的日常造型增添一点复古魅力。 | 25 | https://storage… |
鞋 | 运动鞋#brandA | 戴出舒适自在的时尚穿搭... | 40 | https://storage… |
鞋 | 运动鞋#brandB | 经典功能与现代材质... | 50 | https://storage… |
对于此表,从 DynamoDB 到 Bigtable 的映射非常简单:将 DynamoDB 的复合主键转换为复合 Bigtable 行键。您可以创建一个包含同一组列的列族 (SKU)。
SKU | |||
---|---|---|---|
行键 | 说明 | Price | 缩略图 |
帽子#fedoras#brandA | 采用优质羊毛制作... | 30 | https://storage… |
帽子#fedoras#brandB | 经久耐用的防水帆布... | 28 | https://storage… |
帽子#新闻男孩#品牌 | 为您的日常造型增添一点复古魅力。 | 25 | https://storage… |
鞋子#运动鞋#brandA | 戴出舒适自在的时尚穿搭... | 40 | https://storage… |
鞋子#运动鞋#品牌 B | 经典功能与现代材质... | 50 | https://storage… |
单表设计模式
单一表设计模式将关系型数据库中的多个表整合到 DynamoDB 中的单个表中。您可以采用上例中的方法,并在 Bigtable 中按原样复制此架构。但是,最好是解决此过程中架构的问题。
在此架构中,分区键包含视频的唯一 ID,这有助于共置与该视频相关的所有属性,加快访问速度。鉴于 DynamoDB 的内容大小限制,您无法在一行中添加不限数量的自由文本注释。因此,使用 VideoComment#reverse-timestamp
模式的排序键将每条评论设为分区内的单独行,并按时间倒序排序。
假设该视频有 500 条评论,并且所有者想要移除该视频。 这意味着,您还需要删除所有评论和视频属性。 要在 DynamoDB 中执行此操作,您需要扫描此分区中的所有键,然后发出多个删除请求,并遍历每个请求。DynamoDB 支持多行事务,但此删除请求过大,无法在单个事务中执行。
主键 | 特性 | |||
---|---|---|---|---|
分区键 | 排序键 | UploadDate | 格式 | |
0123 | 视频 | 2023-09-10T15:21:48 | {"480": "https://storage...", "720": "https://storage...", "1080p": "https://storage..."} | |
视频评论#98765481 | 内容 | |||
我真的很喜欢。特效非常好用。 | ||||
视频评论#86751345 | 内容 | |||
1:05 时似乎出现了音频小故障。 | ||||
VideoStatsLikes | 计数 | |||
3 | ||||
VideoStatsViews | 计数 | |||
156 | ||||
0124 | 视频 | 2023-09-10T17:03:21 | {"480": "https://storage…", "720": "https://storage…"} | |
视频评论#97531849 | 内容 | |||
我与所有朋友分享了此内容。 | ||||
视频评论#87616471 | 内容 | |||
这种风格让我想起了一位电影导演,但我根本无能为力。 | ||||
VideoStats | ViewCount | |||
45 |
在迁移时修改此架构,以便简化代码并降低数据请求的速度和成本。Bigtable 行的容量比 DynamoDB 项大得多,并且可以处理大量注释。如需应对视频收到数百万条评论的情况,您可以设置垃圾回收政策,以便仅保留固定数量的最新评论。
由于可以更新计数器,而不会产生更新整个行的开销,因此您也不必拆分计数器。您不必使用 UploadDate 列,也不必计算反向时间戳并将其设置为排序键,因为 Bigtable 时间戳会自动为您提供按时间逆序排序的注释。这样可以显著简化架构,而且在视频被移除后,您可以通过一个请求以事务方式移除该视频所在的行(包括所有评论)。
最后,由于 Bigtable 中的列按字典顺序排序,因此作为一项优化,您可以重命名这些列,以便在单个读取请求中实现从视频属性到前 N 条最新评论的快速范围扫描,而这也是您在加载视频时需要执行的操作。然后,您可以在观看者滚动浏览时翻阅其余评论。
特性 | ||||
---|---|---|---|---|
行键 | 格式 | 赞过的视频 | 视图 | UserComments |
0123 | {"480": "https://storage...", "720": "https://storage...", "1080p": "https://storage..."} @2023-09-10T15:21:48 | 3 | 156 | 我真的很喜欢。特效非常好用。@
2023-09-10T19:01:15 1:05 处似乎出现了音频小故障。@ 2023 年 9 月 10 日 16:30:42 |
0124 | {"480": "https://storage...", "720":"https://storage..."} @2023-09-10T17:03:21 | 45 | 这种风格让我想起了一位电影导演,但我根本无能为力。@2023-10-12T07:08:51 |
相似性列表设计模式
请考虑此设计的一个略有不同的版本,DynamoDB 通常将其称为相邻列表设计模式。
主键 | 特性 | |||
---|---|---|---|---|
分区键 | 排序键 | DateCreated | 详细信息 | |
Invoice-0123 | Invoice-0123 | 2023-09-10T15:21:48 | {"discount": 0.10, "sales_tax_usd":"8", "due_date":"2023 年 10 月 3 日.."} |
|
Payment-0680 | 2023-09-10T15:21:40 | {"amount_usd": 120, "bill_to":"John...", "address":"Abc St..."} |
||
Payment-0789 | 2023-09-10T15:21:31 | {"amount_usd": 120, "bill_to":"小珍...", "address":"Xyz 街 13 号..."} |
||
Invoice-0124 | Invoice-0124 | 2023-09-09T10:11:28 | {"discount": 0.20, "sales_tax_usd":"11", "due_date":"2023-10-03.."} |
|
Payment-0327 | 2023-09-09T10:11:10 | {"amount_usd": 180, "bill_to":"Bob...", "address":"Cba St...321 号..."} |
||
Payment-0275 | 2023-09-09T10:11:03 | {"amount_usd": 70, "bill_to":"Kate...", "address":"21 Zyx St..."} |
在此表中,排序键不是基于时间,而是基于付款 ID,因此您可以使用不同的宽列模式,使这些 ID 在 Bigtable 中成为单独的列,其优势与上一个示例类似。
账单 | 付款 | |||
---|---|---|---|---|
行键 | 详细信息 | 0680 | 0789 | |
0123 | {"discount": 0.10, "sales_tax_usd":"8", "due_date":"2023 年 10 月 3 日.."} @ 2023-09-10T15:21:48 |
{"amount_usd": 120, "bill_to":"John...", "address":"123 Abc St..."} @ 2023-09-10T15:21:40 |
{"amount_usd": 120, "bill_to":"Jane...", "address":"13 Xyz St..."} @ 2023-09-10T15:21:31 |
|
行键 | 详细信息 | 0275 | 0327 | |
0124 | {"discount": 0.20, "sales_tax_usd":"11", "due_date":"2023-10-03.."} @ 2023-09-09T10:11:28 |
{"amount_usd": 70, "bill_to":"Kate...", "address":"21 Zyx St..."} @ 2023-09-09T10:11:03 |
{"amount_usd": 180, "bill_to":"Bob...", "address":"Cba St..."} @ 2023-09-09T10:11:10 |
如前面的示例所示,如果架构设计得当,Bigtable 的宽列模型可能非常强大,能够满足许多用例,这些用例需要在其他数据库中执行成本高昂的多行事务、二级索引或 on-delete 级联行为。
后续步骤
- 了解 Bigtable 架构设计。
- 了解 Bigtable 模拟器。
- 探索有关 Google Cloud 的参考架构、图表和最佳实践。查看我们的云架构中心。