面向 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 操作会消耗所更新项的最大大小(更新之前或之后),即使更新涉及项的属性子集也是如此。
节点:负责读取和写入数据的虚拟计算资源。集群已转换为读取、写入和扫描吞吐量限制的节点数。您可以根据延迟时间目标、请求数和载荷大小的组合调整节点数量。

与 RCU 和 WCU 之间存在显著差异,SSD 节点为读取和写入操作提供相同的吞吐量。如需了解详情,请参阅典型工作负载下的性能
分区 :由与节点共置的固态硬盘 (SSD) 支持的连续行块。

每个分区都有硬性限制,即 1,000 个 WCU、3,000 个 RCU 和 10 GB 数据。
平板电脑 :由所选存储媒介(SSD 或 HDD)支持的连续行块。

表会被分成多个片以平衡工作负载。这些片不会存储在 Bigtable 中的节点上,而是存储在 Google 的分布式文件系统中。这可以在伸缩时快速地重新分布数据,并且可通过维护多个副本提供更高的耐用性。
全局表 :一种通过自动在多个区域中传播数据更改来提高数据可用性和耐用性的方法。 复制 :一种通过自动在多个区域或同一区域内的多个地区传播数据更改来提高数据可用性和耐用性的方法。
不适用 (N/A) 应用配置文件 :用于指示 Bigtable 如何将客户端 API 调用路由到实例中相应集群的设置。您还可以使用应用配置文件作为标记来细分归因指标。

地理位置复制

复制用于满足客户以下方面的要求:

  • 在发生可用区级或区域级故障时实现业务连续性。
  • 将您的服务数据放在靠近最终用户的位置,以便低延迟传送。
  • 如果您需要在一个集群上实现批量工作负载并依赖于复制来提供服务集群,则可以使用工作负载隔离功能。

Bigtable 支持在提供 Bigtable 的最多 8 个 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
BatchGetItemQueryScan
`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 没有这样的概念,它需要复杂的架构设计来支持版本控制。此方法涉及为每项内容创建两个副本:一个副本的版本号前缀为 0(例如 v0_),另一个副本的版本号前缀为 1(例如 v1_)。每次更新内容时,您都将在更新版本的排序键中使用下一个较高的版本前缀,并将更新的内容复制到版本前缀为零的项目中。这可确保能够使用零前缀找到任何项的最新版本。此策略不仅需要维护应用端逻辑,而且会使数据写入的成本很高且速度很慢,因为每次写入都需要读取先前的值加上两次写入。

多行事务与大行容量

Bigtable 不支持多行事务。但是,由于它允许您存储比 DynamoDB 中的项大得多的行,因此通常可以通过设计架构将相关项分组到共享行键下,从而实现预期的事务性。如需查看说明此方法的示例,请参阅单表设计模式

存储大型值

由于 DynamoDB 项(类似于 Bigtable 行)的大小限制为 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 缩略图
帽子#女帽#品牌 A 采用优质羊毛制成... 30 https://storage…
帽子#软呢帽#brandB 耐用防水画布适用于... 28 https://storage…
帽子#newsboy#brandB 为日常造型增添一丝复古魅力。 25 https://storage…
鞋子#运动鞋#品牌 A 走出时尚与舒适... 40 https://storage…
鞋子#运动鞋#brandB 经典特色与当代材料相得益彰... 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

在迁移时修改此架构,以便简化代码,并以更快、更低的价格发出数据请求。与 DynamoDB 项相比,Bigtable 行的容量要大得多,并且可以处理大量注释。如需处理视频收到数百万条评论的情况,您可以设置垃圾回收政策,仅保留固定数量的最新评论。

由于可以更新计数器,而不会产生更新整行的开销,因此您也无需拆分计数器。您不必使用 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-09-10T16: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-03.."}
Payment-0680 2023-09-10T15:21:40 {"amount_usd": 120, "bill_to":"John...",
"address":"123 Abc St..."}
Payment-0789 2023-09-10T15:21:31 {"amount_usd": 120, "bill_to":"Jane...",
"address":"13 Xyz St..."}
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":"321 Cba St..."}
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-03.."}
@ 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":"321 Cba St..."}
@ 2023-09-09T10:11:10

正如您在前面的示例中看到的,借助正确的架构设计,Bigtable 的宽列模型可能非常强大,并且可以提供许多需要在其他数据库中使用昂贵的多行事务、二级索引或删除时级联行为的使用场景。

后续步骤