无服务器

从关系DB到单个DynamoDB表:逐步探索

只是因为它's NoSQL, doesn't mean it's non-relational
Forrest Brazeal. Trek10 191210 171202
Forrest Brazeal. | 2019年1月22日

在从AWS RE看的所有会议中:发明2018年,我最喜欢的是这种令人困惑的小组专业知识来自AWS主要技术专家和认证的外太空巫师Rick Houlihan。

说真的,看那个视频,然后回到这篇文章。你不会失望。

瑞克在一罐蠕虫上裂开盖子,这些蠕虫是我们许多设计DynamoDB表试图避免的蠕虫:DynamoDB不仅仅是简单项目查找的键值商店的事实。如果正确地设计它,则单个DynamoDB表可以处理合法多表关系数据库的访问模式,而不会破坏汗水。

当然,那个小短语“设计得当”是警告。瑞克的视频,和相关文件我怀疑他曾经掌握过,凭借有关如何构造一个DynamoDB表的建议,这将在任意水平刻度下匹配您的关系数据库的查询性能。

虽然不是,这是沉重的东西,特别是对于美国未经认证的外太空巫师。

所以在这篇文章中,我想通过一些DynamoDB在逐步的细节中通过一些DynamoDB单表设计考虑。我们不会涵盖每种可能的设计模式,但希望您将开始了解可能的用例和不可避免的权衡。我们将结束最终问题:在关系数据库仍然存在时,这是一个好主意,如,就在那儿?

从RDB到DynamoDB:一个实际的例子

公平警告:我深深潜入!如果您只想跳到高级结论,拿快捷方式!

那么我们应该是什么关系数据库,呃,动态化?我决定使用我可以想到的最多的SQL-Y榜样:北风,经典的关系数据库用于将Microsoft Access产品返回90年代。

这是完整的Northwind Erd。它并不巨大,但它至少与许多现代微服务的数据要求一样复杂,您可能希望使用DynamoDB返回。

lo和behold,Northwind架构的示例数据是可清除CSV表格在github上。我们将忽略几张辅助表,专注于“大八”:类别,客户,员工,订单/订单详情,产品,托运人和供应商。

我已经包括创建DynamoDB表所需的所有代码,并如整个帖子中所示加载数据这个github repo.。随意查看它并搭配!

一步步

现在,我们如何将我们的ERD和CSV表转换为DynamoDB表?

第1步:定义您认为需要的访问模式

马上,我们突出了DynamoDB和关系数据库之间的巨大差异:我们的数据模型将全部务实,而不是理论上自我一致。我们要将我们的桌面塑造,他们需要用数据需要做的事情,有点像将绝缘泡沫喷涂到屋顶上。

在现实世界中,我们会从App团队,潜在用户等中收集这些要求。这不是一个真正的用例,所以我们必须通过查看ERD来发明一些访问模式。以下是我提出的一些任意查询要求:

  1. 通过员工ID获取员工
  2. 获取员工的直接报告
  3. 停产产品
  4. 列出给定产品的所有订单
  5. 获得最近的25个订单
  6. 按名称获取托运人
  7. 通过联系人姓名获取客户
  8. 列出订单中包含的所有产品
  9. 通过国家和地区获得供应商

所有这些都是简单的SQL查询,涉及大多数加入。 (我们将为未来的帖子保存写模式。)但请记住,我们没有在DynamoDB中加入或组。相反,我们必须以这样的方式构建我们的数据,即它在表中的“预先加入”。

步骤2:使用三个通用属性创建DynamoDB表:“分区密钥”,“排序键”和“数据”

这将我们带来了DynamoDB单表设计中最重要的戒备之一:

属性名称与属性值没有关系。

不仅是我们的“钥匙值商店”模式;在某种程度上,它也是无钥匙。我们需要习惯于将DynamoDB项上的属性名称视为任意。我们在表上的“分区键”属性可能包含不同类型的值,具体取决于它是订单,产品,员工或其他方式:

我知道,在同一属性中存储不同类型的数据感觉奇怪和奇迹。但它实际上超强了。这种技术被称为索引超载,它将使我们能够将大约缩短的访问模式升级为非常少量的索引。

The three generic attributes will be used to support two indexes: the main table index which uses pk as the partition and sk as the sort key, and a global secondary index which uses sk as the partition and data as the sort.

无论如何,关于索引的大小是多少?一般来说,如果您将自己限制为“获取”(单个项目上的键/值查找)和“查询”(条件查找具有相同分区密钥的项目,但不同的范围/排序键) )。扫描,您不分青红皂白地吞噬了桌子的所有物品,是一种缓慢,昂贵的反饰特。有用的获取和查询需要......有用的索引。所以我们在这里。

这两个索引,正如我们所看到的那样,将开辟大量的访问模式。表中的其他属性可以根据您想要的任何内容命名;它们不必在物品之间保持一致。但即使您为每个项目提供随机名的每个属性,它也不会影响表格的行为。 (它只是让桌面布局更加努力阅读和理解......我们将在下面进一步讨论。)

步骤3:在每个实体(非连接)表中为每个记录创建DynamoDB表中的项目

Each Customer, each Order, each Shipper record gets an item in our new table. In each of our cases, we’ll make the pk attribute correspond to the primary key of the relational record. The skdata attributes, though, we’ll vary based on the kinds of queries we need to write. See the breakdown below:

我们已经遗漏了“OrderDetails”现在加入表;它会在下一步中得到特殊处理。

让我们在这里注意几个技巧:

  • The Order, Product, and Supplier records use a static value as the partition key for GS1. This lets us look up all items of a particular type (such as all orders that match a date range) without resorting to an expensive scan operation. You can think of this as a workaround for the loss of our precious attribute keys: we’re using a value as a key instead.
  • 我们使用了一个名为a的复合值分层排序键 as the data field for the Customer and Supplier records. By combining all the address details into one field, we can get country, region and city lookups for the price of a single GSI.
  • 我们使用“已停止”值作为产品项的GSI上的排序键。假设我们只填充该价值的已停止产品(在原始Northwind数据中不正确),我们可以搜索已停止的项目,而无需扫描整个“产品”分区。这种技术称为a稀疏索引.

我们此时基本上与我们的数据一起玩方块,在我们有限的GSI插槽中滑出不同的值,以获取最大实用程序。我们没有完成,因为我们仍然需要......

为什么我们如此沉迷于最小化全球二级指标?在此表上拍摄一吨索引,它不会更容易?很长一段时间,答案是否定的; DynamoDB表的硬限制为5 GSI。 DynamoDB最近刚提出了这一限制一个柔软的20,意味着您可能在表格上有一个未定义数量的GSI。

但很多GSIS使几何上更昂贵,每次更新项目时都会消耗额外的容量单位。因此,如果我们可以将我们的查找落入最小可能的索引足迹,我们将赢得成本和性能。

第4步:代表与邻接列表的多对多关系

DynamoDB最佳实践从图论借用概念邻接清单,这是......有点滑溜溜的概念。要挂在图表的想法片刻,您可以考虑到我们在桌面中放置的所有项目,到目前为止是“节点”记录。它们对应于实体,如客户和订单。我们现在正在创建一些额外的“边缘”记录,该记录代表节点之间的多对多关系。

In the Northwind dataset, the many-to-many relationship we’ll focus on is expressed in the OrderDetails join table. An order can have many products, one product can appear in many orders, and the attributes of that relationship are expressed in OrderDetails. We’ll model this relationship by placing the OrderDetails records in the Order partition of our table.

为什么我们再次将所有这些东西放在一张桌子上?DynamoDB文档强调推荐使用尽可能少的表,通常每个应用程序/服务通常一个,除非您有巨大的分歧模式。将相关数据定位在一起将为您提供Dynamo的性能和规模优势,而无需通过HTTP查询多个表的延迟和挫折,并尝试“加入”它们客户端。

也就是说,我看到了许多应分成单独的DynamoDB表的关系数据库,因为相同的数据库被用作各种无关数据的倾倒地。 70-GB Postgres数据库中的访问日志表无需使用您的产品和订单数据在同一DynamoDB表中。

这是什么让我们有什么?我们现在有能力查询主表分区以按顺序获取所有产品。我们可以查询GS1 PK在给定产品的所有订单上进行反向查找。这是邻接列表模式。您可以在Northwind数据中使用“雇用”中的“雇用”加入表来尝试,我们没有在此处包含哪些。如果您进一步掌握了,您可能需要将此访问模式分解为自己的GSI。

步骤5(可选):创建更多GSI以支持其他访问模式

相信它与否,即使我们在步骤2中使用的所有诀窍,一个GSI可能不足以支持每种可能的查询! (令人震惊的,我知道。)好消息是,如果需要,您可以添加额外的GSI,而不完全扰乱仔细拼凑的俄罗斯方块板。 dynamodb文档具有一个很好的例子使用专门构造的分区添加第二个GSI并排序键以处理某些类型的范围查询。

但是,在我们的情况下,主表分区加上一个GSI足以处理我们在步骤1.中定义的所有使用情况。让我们分解查询:

碎片怎么样?我们一直在思考如何让我们的单表查询简单,但不一定是如何快速制作它们。即使是DynamoDB的新自适应容量功能,您希望保持访问模式平滑,因此您没有在单个分区上不成比例的负载。这通常涉及使用随机密钥创建索引。亚历克斯德布里有一个奇妙的细分在他的dynamodb中的作品指南中,当您可能需要它时。 (特别是,使用静态分区密钥,如“订单”,即时对我们的GSIS表示很重要,这是一个包装成单个分区的很多记录。)

你可以看到所有这些查询的工作示例在随附的repo中使用AWS Python SDK。此外,我们保留了桌子中每个实体的单个键值查找,因此我们没有离DynamoDB的根源过得太远。

建立一个无服务器的架构?了解有关单表设计,处理复杂应用程序和来自Trek10 DynamoDB专家的新访问模式的更多信息。

请求研讨会

什么不能我们的确是?

我们现在有一个基本的蓝图将关系数据库转换为单个DynamoDB表。但请记住,这是一种喷雾泡沫的数据方法。与天花板的轮廓中的绝缘一样硬化,我们的DynamoDB单表数据模型都是非正式的不灵活。它不一定要满足新的访问模式。

例如,假设我们需要在给定类别中查看所有产品。 “产品”记录有一个类别,但目前不包括在我们的任何索引中。我们的选择是:

  1. 查询所有产品,按类别ID(不是最佳查询)的类别,或
  2. 在我们的一个现有分区中突破新项目,该分区通过类别ID索引产品数据(创建更多重复数据,可能更难管理),或
  3. 使用产品ID创建一个新的GSI作为分区和类别ID,作为排序键(增加表成本)

正如你所看到的,权衡比比皆是!只有您可以决定哪个选项对应用程序的长期健康以及开发人员的理智来说最有意义。您添加了通用属性的GSIS越多,此表将越难以读取和理解,而不会加载支持文档。

事实上,一个优化的单表DynamoDB布局看起来更像是机器代码,而不是简单的电子表格 - 尽管所有的定制,它需要人类欺诈来创建它。

这导致最重要的问题:

在一个DynamoDB表中为我的关系数据库建模真的是一个好主意吗?

大约一年前,我写了一个相当流行的文章“为什么DynamoDB不适合所有人”。当时发出的DynamoDB的许多技术批评(缺乏备份/恢复等运营控制;由于特征释放的真正令人敬畏的运行,因此已经部分或完全解决了DynamoDB团队。

然而,该文章的核心论点仍然有效:DynamoDB是一个强大的工具,当您正确使用时,但如果您不知道您在做什么是疯狂的用户友好指南。而且你进一步流入了关系建模等宇宙的应用程序,更肯定你最好是你知道你所在的东西。特别是与SQL友好的“无服务器“像Amazon Aurora这样的数据库击中他们的步幅,您可以使用很多完全托管的选项,具有较小的学习曲线。

也就是说,请记住,亚马逊的原始迪迪纸是追求观察与其庞大的Oracle数据库的互动是简单的键值读取,无需连接或其他关系魔法。

以同样的方式,许多超细关系数据集沸腾到相对少量的使用模式。如果您可以通过此帖子中的步骤来识别和实施数据的模式,DynamoDB的规模,性能和低运行开销可能看起来比以往任何时候都更引人注目。

除非你知道,否则你仍然是Microsoft Access的忠实粉丝。

感谢Alex Debrie,Jared Short,Andy Warzon在这篇文章中为提供技术审查。

需要dynamodb专业知识? Trek10已经在那里完成了这一点。如果我们可以帮助您,请随意让我们知道.

作者
Forrest Brazeal. Trek10 191210 171202
Forrest Brazeal.