动机说明:在使用像 DynamoDB 这样的云存储时,我们必须了解存储模型,因为这会直接影响
您的性能、可扩展性和财务成本。它是不同的
而不是使用本地数据库,因为您不仅要为
您存储的数据以及您对其执行的操作
数据。例如,删除记录是一个 WRITE 操作,所以如果
你没有一个有效的清理计划(你的情况是
时间序列数据特别需要一个),您将付出代价。您的
数据模型处理小数据量时不会出现问题
但是当您需要扩展时,肯定会破坏您的计划。那个存在
说,像创建(或不)索引,定义适当的
您的键的属性,创建表分段等将
让整个过程变得与众不同。选择 DynamoDB(或更多
一般而言,键值存储)与任何其他架构一样
决定是有取舍的,你需要清楚地了解
有关存储模型的某些概念,以便能够使用该工具
有效地,选择正确的键确实很重要,但只有
冰山一角。例如,如果你忽略了你是
处理时间序列数据,不管是什么主键或索引
您定义,您的预置吞吐量将不会被优化,因为
它分布在整个表(及其分区)中,而不是
只有经常访问的数据,这意味着未使用的数据是
直接影响您的吞吐量,因为它是相同的一部分
桌子。这会导致以下情况
ProvisionedThroughputExceededException 被“意外”抛出时
您确定您的预置吞吐量应该足以满足您的需求
但是,需要不均匀访问的 TABLE PARTITION
已达到极限(更多详情here)。
下面的帖子有更多细节,但我想给你一些阅读它的动力并理解虽然你现在肯定可以找到一个更简单的解决方案,但这可能意味着在不久的将来你从头开始一堵墙(“墙”可能是高昂的财务成本、性能和可扩展性的限制,或所有这些的组合)。
问:我可以将唯一的通知 ID 作为哈希键,将用户 ID 作为范围键吗?这是否允许我仅通过范围键进行查找,即不提供哈希键?
答: DynamoDB 是 Key-Value 存储,这意味着最有效的查询使用整个 Key(Hash 或 Hash-Range)。仅仅因为您没有密钥而使用Scan 操作来实际执行查询,这绝对是您的数据模型在您的要求方面存在缺陷的迹象。有几件事情需要考虑,并且有许多选项可以避免这个问题(更多详情见下文)。
现在在继续之前,我建议您阅读这篇快速文章以清楚地了解 Hash Key 和 Hash+Range Key 之间的区别:
DynamoDB: When to use what PK type?
您的案例是典型的时间序列数据场景,您的记录会随着时间的推移而过时。您需要注意两个主要因素:
如果您将所有通知放在一个表中并且更频繁地访问最近的通知,则您的预置吞吐量将不会得到有效使用。
您应该将访问次数最多的项目分组到一个表中,以便可以针对所需访问正确调整预置吞吐量。此外,请确保正确定义 Hash Key that will allow even distribution of your data across multiple partitions。
- 以最有效的方式(努力、性能和成本方面)删除过时的数据
文档建议将数据分段到不同的表中,以便在记录过时后删除或备份整个表(请参阅下面的更多详细信息)。
以下是文档中解释与时间序列数据相关的最佳实践的部分:
了解时间序列数据的访问模式
为您创建的每个表指定吞吐量
要求。 DynamoDB 分配和预留资源来处理您的
具有持续低延迟的吞吐量要求。当你设计
您的应用程序和表格,您应该考虑您的应用程序的
访问模式以最有效地利用您的表
资源。
假设您设计了一个表格来跟踪您网站上的客户行为,
例如他们点击的 URL。您可以使用散列和
以客户 ID 作为散列属性的范围类型主键和
日期/时间作为范围属性。在此应用程序中,客户数据
随着时间的推移无限增长;但是,应用程序可能会显示
表中所有项目的访问模式不均匀
最新的客户数据更相关,您的应用程序可能
更频繁地访问最新项目并且随着时间的推移这些项目
访问较少,最终很少访问较旧的项目。如果
这是一种已知的访问模式,您可以考虑一下
在设计表架构时。而不是将所有项目存储在一个
单个表,您可以使用多个表来存储这些项目。为了
例如,您可以创建表来存储每月或每周的数据。为了
存储最近一个月或一周的数据的表,其中数据
访问率高,请求更高的吞吐量和表存储
旧数据,您可以降低吞吐量并节省资源。
您可以通过将“热门”项目存储在一个表中来节省资源
更高的吞吐量设置,以及另一个表中的“冷”项目
较低的吞吐量设置。您只需删除即可删除旧项目
桌子。您可以选择将这些表备份到其他存储
Amazon Simple Storage Service (Amazon S3) 等选项。 删除一个
整个表比删除项目效率高得多
一个接一个,这基本上使您的写入吞吐量翻倍
删除操作与放置操作一样多。
来源:
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForTables.html#GuidelinesForTables.TimeSeriesDataAccessPatterns
例如,您可以按月份对表格进行分段:
Notifications_April, Notifications_May, etc
问:我希望能够查询给定用户的最新 X 通知。
答:我建议使用Query 操作并仅使用具有Range Key 的Hash Key (UserId) 来按Timestamp(日期和时间)。
Hash Key: UserId
Range Key: Timestamp
注意:更好的解决方案是 Hash Key 不仅有 UserId,而且还有另一个连接信息,您可以在查询之前计算这些信息以确保您的 Hash Key 授予您甚至访问您的数据的模式。例如,如果来自特定用户的通知比其他用户更容易访问,则您可以开始使用 热分区...在 Hash Key 中添加额外信息可以降低这种风险。
问:我想获取特定用户的未读通知数。
答:创建一个Global Secondary Index 作为稀疏索引,其中UserId 作为Hash Key,Unread 作为Range Key。 p>
例子:
Index Name: Notifications_April_Unread
Hash Key: UserId
Range Key : Unuread
当您通过哈希键 (UserId) 查询此索引时,您将自动获得所有未读通知,而无需通过与此案例无关的通知进行不必要的扫描。请记住,表中的原始主键会自动投影到索引中,因此如果您需要获取有关通知的更多信息,您可以随时使用这些属性对原始主键执行 GetItem 或 BatchGetItem表。
注意:您可以探索使用除“未读”标志之外的不同属性的想法,重要的是要记住稀疏索引可以帮助您处理此用例(更多详情如下)。
详细解释:
我将有一个稀疏索引来确保您可以查询减少的数据集来进行计数。在您的情况下,您可以使用“未读”属性来标记通知是否已被读取,并使用该属性来创建稀疏索引。当用户阅读通知时,您只需从通知中删除该属性,使其不再显示在索引中。以下是文档中明确适用于您的场景的一些指南:
利用稀疏索引
对于表中的任何一项,DynamoDB 只会写一个对应的
索引条目,如果是索引范围键
属性值存在于项目中。如果范围键属性
没有出现在每个表项中,索引被认为是稀疏的。
[...]
要跟踪未结订单,您可以在 CustomerId(哈希)和
IsOpen(范围)。只有表中定义了 IsOpen 的那些订单
将出现在索引中。然后,您的应用程序可以快速且
通过查询索引有效地找到仍然打开的订单。
例如,如果您有数千个订单,但数量很少
打开后,应用程序可以查询索引并返回
每个未结订单的 OrderId。您的应用程序将执行
读取次数明显少于扫描整个文件所需的次数
客户订单表。 [...]
您无需将任意值写入 IsOpen 属性,而是
可以使用不同的属性来产生有用的排序顺序
在索引中。为此,您可以创建一个 OrderOpenDate 属性
并将其设置为下订单的日期(仍然删除
订单完成后的属性),并创建 OpenOrders
具有架构 CustomerId (hash) 和 OrderOpenDate (range) 的索引。
这样,当您查询索引时,项目将以
更有用的排序顺序。[...]
这样的查询可以非常高效,因为
索引将显着小于中的项目数
桌子。此外,您投射到
索引,您将从索引中消耗的读取容量单位越少。
来源:
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GuidelinesForGSI.html#GuidelinesForGSI.SparseIndexes
在下面找到以编程方式创建和删除表所需的操作的一些参考:
创建表格
http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CreateTable.html
删除表格
http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteTable.html