从 DynamoDB 迁移到 Bigtable
Bigtable 和 DynamoDB 是分布式键值对存储区,可以支持每秒数百万次的查询次数 (QPS),提供可扩缩至 PB 级数据的存储空间,并容忍节点故障。
本文档适用于想要迁移到 Bigtable 的 DynamoDB 开发者和数据库管理员。如果您想设计应用以将 Bigtable 用作数据存储区,本指南也很有用。
首先,请使用 Google 提供的迁移工具,该工具可帮助您从 DynamoDB 迁移到 Bigtable。本页介绍了迁移工具,比较了这两种数据库系统,并介绍了在迁移之前需要了解的基础架构和交互细节方面的差异。
开始使用 DynamoDB 到 Bigtable 的迁移工具
Google Cloud 专业服务团队提供了一款开源迁移工具,可简化从 DynamoDB 到 Bigtable 的数据迁移。该工具可自动执行将数据导入 Google Cloud 并加载到 Bigtable 中的过程。
使用该工具导出 DynamoDB 表,然后将其转移到 Cloud Storage。该工具会从您的 Cloud Storage 存储桶中读取导出的文件,并使用 Dataflow 模板转换数据,使其与 Bigtable 兼容。此转换包括将 DynamoDB 属性映射到 Bigtable 行。然后,Dataflow 作业会将转换后的数据写入您的 Bigtable 表。
如需了解详情或开始使用,请参阅 DynamoDB 到 Bigtable 迁移实用程序。
DynamoDB 和 Bigtable 的比较
本部分将探讨 DynamoDB 和 Bigtable 之间的异同。
控制平面
在 DynamoDB 和 Bigtable 中,控制平面可让您配置容量,以及设置和管理资源。DynamoDB 是一种无服务器产品,与 DynamoDB 的最高互动级别是表级别。在预置容量模式下,您可以在此处预置读写请求单位、选择区域和复制,以及管理备份。 Bigtable 不是无服务器产品;您必须创建一个包含一个或多个集群的实例,这些集群的容量由其拥有的节点数决定。如需详细了解这些资源,请参阅实例、集群和节点。
下表比较了 DynamoDB 和 Bigtable 的控制平面资源。
DynamoDB | Bigtable |
---|---|
表: 具有已定义主键的项的集合。表具有备份、复制和容量设置。 | 实例:一组位于不同 Google Cloud 可用区或区域的 Bigtable 集群,这些集群之间会发生复制和连接路由。复制政策是在实例级层设置的。 集群:一组位于同一地理位置的Google Cloud 可用区中的节点,最好与应用服务器位于同一位置,以减少延迟和复制。通过调整每个集群中的节点数量来管理容量。 表:按行键编入索引的值的逻辑组织。 备份在表级层进行控制。 |
读取容量单位 (RCU) 和写入容量单位 (WCU):
允许每秒读取或写入固定有效载荷大小的单位。对于有效载荷大小较大的每次操作,您需要支付读取或写入单位费用。UpdateItem 操作会消耗更新后或更新前最大更新项所用的写入容量,即使更新仅涉及项属性的子集也是如此。 |
节点:一种负责读取和写入数据的虚拟计算资源。集群拥有的节点数量会影响读取、写入和扫描的吞吐量限制。您可以根据延迟时间目标、请求数和载荷大小的组合来调整节点数。 SSD 节点的读取和写入吞吐量相同,这与 RCU 和 WCU 之间的显著差异不同。如需了解详情,请参阅典型工作负载下的性能。 |
分区: 由与节点共置的固态硬盘 (SSD) 支持的连续行块。 每个分区的写入容量单位 (WCU) 硬性限制为 1,000 个,读取容量单位 (RCU) 硬性限制为 3,000 个,数据硬性限制为 10 GB。 |
平板电脑: 由所选存储介质(SSD 或 HDD)支持的连续行块。 表会被分片为多个片,以平衡工作负载。片不是存储在 Bigtable 的节点上,而是存储在 Google 的分布式文件系统上,这样可以在伸缩时快速重新分发数据,并通过维护多个副本来提供额外的持久性。 |
全局表: 一种通过在多个区域自动传播数据更改来提高数据可用性和持久性的方法。 | 复制: 一种通过在多个区域或同一区域内的多个可用区之间自动传播数据更改来提高数据可用性和耐用性的方式。 |
不适用 (N/A) | 应用配置文件: 指示 Bigtable 如何将客户端 API 调用路由到实例中的相应集群的设置。您还可以将应用配置文件用作归因指标细分标记。 |
地理位置复制
复制功能用于满足客户的以下需求:
- 在发生可用区级或区域级故障时,实现高可用性以保障业务连续性。
- 将服务数据放置在最终用户附近,以便无论他们身在何处,都能以低延迟提供服务。
- 当您需要在某个集群上实现批处理工作负载,并依靠复制功能来为集群提供服务时,需要进行工作负载隔离。
Bigtable 支持将复制的集群分布在最多 8 个 Google Cloud 提供 Bigtable 的区域中的任意数量的可用区中。大多数区域都有三个可用区。如需了解详情,请参阅区域和可用区。
Bigtable 会在多主拓扑中自动跨集群复制数据,这意味着您可以向任何集群读取和写入数据。Bigtable 的复制功能提供最终一致性。如需了解详情,请参阅复制概览。
DynamoDB 提供全局表,以支持跨多个区域的表复制。全局表是多主表,可在区域之间自动复制。复制操作具有最终一致性。
下表列出了复制概念,并介绍了它们在 DynamoDB 和 Bigtable 中的可用性。
属性 | DynamoDB | Bigtable |
---|---|---|
多主复制 | 可以。 您可以读取和写入任何全局表。 |
可以。 您可以读取和写入任何 Bigtable 集群。 |
一致性模型 | 最终一致性。 对于全局表,在区域级实现读己所写 (read-your-writes) 一致性。 |
最终一致性。 如果您将读取和写入操作都发送到同一集群,则所有表都可实现集群级读己所写一致性。 |
复制延迟时间 | 无服务等级协议 (SLA)。 秒 |
无 SLA。 秒 |
配置粒度 | 表级。 | 实例级。 一个实例可以包含多个表。 |
实现 | 创建全局表,并在每个所选区域中包含一个表副本。 区域级。 通过将表转换为全局表,在副本之间自动复制。 必须为表启用 DynamoDB Streams,并且流中包含项目的新旧映像。 删除某个区域即可移除该区域中的全局表。 |
创建具有多个集群的实例。 该实例中的集群之间会自动进行复制。 可用区级。 向 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 |
---|---|
标量类型: 在服务器响应中以数据类型描述符令牌的形式返回。 | 字节: 字节在客户端应用中转换为预期类型。 增量将值解读为 64 位大端序有符号整数 |
Set: 包含唯一元素的无序集合。 | 列族: 您可以使用列限定符作为集合成员名称,并为每个列限定符提供单个 0 字节作为单元格值。集合成员在其列族中按字典顺序排序。 |
映射: 键值对的无序集合,其中键是唯一的。 | 列族 使用列限定符作为映射键,使用单元格值作为值。地图键按字典顺序排序。 |
列表: 已排序的项集合。 | 列限定符 使用插入时间戳可实现与 list_append 行为等效的效果,使用插入时间戳的反向值可实现 prepend 行为。 |
架构设计
在架构设计中,一个重要的考虑因素是数据的存储方式。Bigtable 和 DynamoDB 之间的主要区别包括它们在以下方面的处理方式:
- 单值的更新
- 数据排序
- 数据版本控制
- 存储大值
单值的更新
即使更新只涉及项目属性的子集,DynamoDB 中的 UpdateItem
操作也会消耗“之前”和“之后”项目大小中较大者的写入容量。这意味着,在 DynamoDB 中,您可能会将经常更新的列放在单独的行中,即使从逻辑上讲,它们与其他列属于同一行。
无论某个单元格是给定行中的唯一列,还是数千列中的一列,Bigtable 都能以同样高效的方式更新该单元格。如需了解详情,请参阅简单写入。
数据排序
DynamoDB 会对分区键进行哈希处理并随机分配,而 Bigtable 会按行键的字典顺序存储行,并将所有哈希处理留给用户。
随机密钥分布并非适用于所有访问模式。它降低了出现热门行范围的风险,但会使涉及跨分区边界扫描的访问模式变得成本高昂且效率低下。这些无界扫描很常见,尤其是在具有时间维度的使用情形中。
处理此类访问模式(跨分区边界的扫描)在 DynamoDB 中需要二级索引,但在 Bigtable 中不需要。虽然您可以在 Bigtable 中设计字典顺序行键,以高效处理多种扫描模式,但 Bigtable 还支持异步二级索引,您可以将其实现为持续具体化的视图,以便为替代查询模式提供高效的最终一致性查找。同样,在 DynamoDB 中,查询和扫描操作限制为扫描 1 MB 的数据,超出此限制时需要分页。Bigtable 没有此类限制。
尽管 DynamoDB 的分区键是随机分布的,但如果所选分区键无法均匀分配流量,从而对吞吐量产生不利影响,则 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 中的可能外观。
主键 | 属性 | |||
---|---|---|---|---|
分区键 | 排序键 | 说明 | 价格 | 缩略图 |
帽子 | 费多拉帽#brandA | 采用优质羊毛制成… | 30 | https://storage… |
帽子 | fedoras#brandB | 采用耐用的防水帆布制成,可用于.. | 28 | https://storage… |
帽子 | newsboy#brandB | 为日常造型增添一丝复古魅力。 | 25 | https://storage… |
鞋子 | 运动鞋#brandA | 穿上…,时尚舒适地出门 | 40 | https://storage… |
鞋子 | 运动鞋#brandB | 采用现代材料的经典功能… | 50 | https://storage… |
对于此表,从 DynamoDB 到 Bigtable 的映射非常简单:您只需将 DynamoDB 的复合主键转换为复合 Bigtable 行键即可。您创建一个包含相同列集的列族 (SKU)。
SKU | |||
---|---|---|---|
行键 | 说明 | 价格 | 缩略图 |
帽子#费多拉帽#品牌 A | 采用优质羊毛制成… | 30 | https://storage… |
帽子#浅顶软呢帽#品牌 B | 采用耐用的防水帆布制成,可用于.. | 28 | https://storage… |
hats#newsboy#brandB | 为日常造型增添一丝复古魅力。 | 25 | https://storage… |
鞋类#运动鞋#品牌 A | 穿上…,时尚舒适地出门 | 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…"} | |
VideoComment#98765481 | 内容 | |||
我非常喜欢这项功能。特效非常棒。 | ||||
VideoComment#86751345 | 内容 | |||
1:05 处似乎出现了音频故障。 | ||||
VideoStatsLikes | 计数 | |||
3 | ||||
VideoStatsViews | 计数 | |||
156 | ||||
0124 | 视频 | 2023-09-10T17:03:21 | {"480": "https://storage…", "720": "https://storage…"} | |
VideoComment#97531849 | 内容 | |||
我已将此内容分享给所有好友。 | ||||
VideoComment#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-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 的宽列模型可以非常强大,并能实现许多用例,而这些用例在其他数据库中需要使用昂贵的多行事务、二级索引或级联删除行为。
后续步骤
- 了解 Bigtable 架构设计。
- 了解 Bigtable 模拟器。
- 探索有关Google Cloud的参考架构、图表和最佳实践。查看我们的云架构中心。