Amazon DynamoDB
开发人员指南 (API Version 2012-08-10)
AWS 服务或AWS文档中描述的功能,可能因地区/位置而异。请点击 Amazon AWS 入门,可查看中国地区的具体差异

针对项目的最佳实践

在 DynamoDB 中处理项目时,您需要考虑如何获取最佳性能,如何降低预置吞吐量成本,以及如何避免操作受限 (保持在读取和写入容量单位内)。如果您处理的项目超出 DynamoDB 中的限制 所述的项目大小上限,则您需要考虑如何处理该状况。本节提供解决这些问题的最佳实践。

使用一对多表而不是大型属性集合

如果您的表中的项目存储很多集合类型属性 (例如数字集或字符串集),请考虑删除该属性并将表分成两个表。要在这些表之间形成一对多关系,请使用主键。

创建表并加载示例数据 一节的 Forum、Thread 和 Reply 表就是这种一对多关系的绝佳示例。举例来说,在 Thread 表中,每个项目都对应一个论坛主题,在 Reply 表中存储了针对每个主题的一个或多个回复。

您无需使用单独的表将回复存储为项目,只需在同一表中存储话题和回复即可。对于每个话题,您可以将所有回复存储在一个字符串集类型的属性中;但是,使用单独的表存储话题和回复数据有以下几个方面的好处:

  • 如果将回复存储为表中的项目,则您可以存储任意数量的回复,因为 DynamoDB 表中可以存储任意数量的项目。

    如果您将回复存储为 Thread 表中的属性值,那么您会受到项目大小上限的约束,项目大小上限会限制存储的回复数量。(请参阅 DynamoDB 中的限制)

  • 当您检索某个 Thread 项目时,您不必过于关注预置吞吐量,因为您只需检索话题数据,而不是该话题的所有回复。

  • 通过查询,您只能检索表中的部分项目。将回复存储在单独的 Reply 表中后,您可以通过查询 Reply 表,只检索回复的子集 (例如,某个特定日期范围内的数据)。

    如果您将回复存储为集合类型的属性值,那么您必须始终检索所有回复,这样占用的预置吞吐量会比所需的吞吐量高。

  • 向进程添加新回复时,您只能向 Reply 表添加一个项目,此操作仅会针对单个 Reply 项目产生预置吞吐量成本。如果回复存储在 Thread 表中,无论您何时话题中添加单个用户回复,您都需要支付写入整个 Thread 项目 (包括所有回复) 的所有费用。

压缩大属性值

如果值很大,在将值存储到 DynamoDB 之前,您可以对其进行压缩。执行此操作可以降低存储和检索此类数据的成本。压缩演算法 (例如 GZIP 或 LZO) 会产生二进制数据输出。然后,您可以将此输出数据存储在 Binary 属性类型中。

例如,创建表并加载示例数据 一章中的 Reply 表中存储论坛用户写入的消息。这些用户回复可能包括非常长的文本字符串,这些内容最适合压缩。

有关演示如何在 DynamoDB 中压缩长消息的示例代码,请参阅:

在 Amazon S3 中存储大属性值

目前,DynamoDB 会限制您存储在表中的项目的大小。有关更多信息,请参阅 DynamoDB 中的限制。然而,您的应用程序可能需要在某一项目中存储超出 DynamoDB 大小上限的数据。要解决此问题,您可以将大属性存储为 Amazon Simple Storage Service (Amazon S3) 中的数据元,并在项目中存储数据元标识符。您还可以在 Amazon S3 在使用数据元元数据支持,将相应项目的主键值存储为 Amazon S3 数据元元数据。使用元数据有助于日后维护您的 Amazon S3 元数据。

例如,来看一下 创建表并加载示例数据 一节中介绍的 ProductCatalog 表。ProductCatalog 表中的项目存储有关物品价格、说明、书本作者以及其他产品维度的信息。如果您想要存储每个产品的图像,那么这些图像可能会非常大。您可以选择将图像存储在 Amazon S3 中,而不是 DynamoDB 中。

以下是使用此方法时需要注意的重要事项:

  • 由于 DynamoDB 不支持跨 Amazon S3 和 DynamoDB 的事务,因此您的应用程序必须处理故障,并负责清理孤立的 Amazon S3 数据元。

  • Amazon S3 限制数据元标识符的长度,因此您必须以符合此限制和其他 Amazon S3 约束的方式整理您的数据。有关更多信息,请参阅 Amazon Simple Storage Service 开发人员指南

将大属性划分到多个项目

如果您需要在单个项目中存储大于 DynamoDB 所允许上限的数据,那么您可以在多个项目中存储该数据,将其作为大型“虚拟项目”数据块。要获取最佳结果,请将数据块存储在具有简单主键 (分区键) 的独立表中,并使用批量操作 (BatchGetItemBatchWriteItem) 来读取和写入数据块。此方法有助于您在表分区中保持工作负载均匀分布。

例如,来看一下 创建表并加载示例数据 一章中介绍的 ForumThreadReply 表。Reply 表中的项目包含论坛用户写入的论坛消息。由于 DynamoDB 中规定项目大小的上限为 400 KB,因此每条回复的长度也有限制。对于大型回复,您可以将回复消息分为多个数据块,然后将每个数据块写入各自具有简单主键 (分区键) 的新 ReplyChunks 表的独立项目中,而不在 Reply 表中存储整个项目。

每个数据块的主键都是由其“父级”回复项目的主键、版本号和序列号组合而成。序列号决定了数据块的顺序。版本号确保当大型回复稍后更新时,系统会自动更新该内容。此外,在更新之前创建的数据块不会与更新后创建的数据块混淆。

您还需要更新带有数据块数量的“父级”回复项目,以便在需要检索回复的所有数据块时,您可以了解需要查找的数据块数量。

举例说明,以下内容介绍的是这些项目如何在 ReplyReplyChunks 表中显示:

Reply

Id ReplyDateTime 消息 ChunkCount ChunkVersion
"DynamoDB#Thread1" "2012-03-15T20:42:54.023Z" 3 1
"DynamoDB#Thread2" "2012-03-21T20:41:23.192Z" "short message"

ReplyChunks

Id 消息
"DynamoDB#Thread1#2012-03-15T20:42:54.023Z#1#1" “较长信息文本的第一部分...”
"DynamoDB#Thread1#2012-03-15T20:42:54.023Z#1#3" “...较长信息文本的第三部分”
"DynamoDB#Thread1#2012-03-15T20:42:54.023Z#1#2" “...较长信息文本的第二部分...”

以下是使用此方法时需要注意的重要事项:

  • 由于 DynamoDB 不支持交叉项目事务,因此您的应用程序需要在写入多个项目处理故障场景,并在读取多个项目时处理项目之间的不一致情况。

  • 如果您的应用程序一次性检索到大量数据,则会生成不均衡的工作负载,并导致意外操作的受限。在检索共享同一分区键值的项目时,此情况尤为明显。

通过使用具有简单主键 (分区键) 的独立表,对大型数据项目进行集块化处理可避免此问题,因为这样可以将每个大型数据块分散到表中。

一个切实可行但并非最佳的解决方案是将每个数据块存储在某个具有复合键,且分区键是“父级”项目主键的表中。选择这一设计的话,检索所有同一“父级”项目数据块的应用程序将会生成不均衡的工作负载,且各个分区的 I/O 分布也将不均衡。