【问题标题】:DynamoDB table/index schema design for querying multi-valued attributes用于查询多值属性的 DynamoDB 表/索引架构设计
【发布时间】:2019-05-08 17:07:28
【问题描述】:

我正在构建一个 DynamoDB 应用程序,该应用程序最终将为大量(数百万)用户提供服务。目前应用的项目架构很简单:

{ 
  userId: "08074c7e0c0a4453b3c723685021d0b6",  // partition key
  email: "foo@foo.com",
  ... other attributes ...
}

当有新用户注册时,或者如果用户想通过电子邮件地址查找其他用户,我们需要通过email 而不是userId 来查找用户。使用当前架构很简单:只需使用以email 作为分区键的全局二级索引。

但我们希望为每个用户启用多个电子邮件地址,而 DynamoDB Query 操作不支持 List-typed KeyConditionExpression。因此,每次用户注册或希望通过电子邮件地址查找其他用户时,我都会权衡几个选项以避免昂贵的Scan 操作。

以下是我计划更改的内容,以便为每个用户启用额外的电子邮件。这是一个好方法吗?有更好的选择吗?

  1. 添加一个排序键列(例如itemTypeAndIndex)以允许每个userId 有多个项目。

      { userId: "08074c7e0c0a4453b3c723685021d0b6", // partition key itemTypeAndIndex: "main", // sort key email: "foo@foo.com", ... other attributes ... }

  1. 如果用户添加第二封、第三封等电子邮件,则为每封电子邮件添加一个新项目,如下所示:

      { userId: "08074c7e0c0a4453b3c723685021d0b6", // partition key itemTypeAndIndex: "Email-2", // sort key email: "bar@bar.com" // no more attributes }

  1. 仍然可以使用相同的全局二级索引(以 email 作为分区键)来查找主要和非主要电子邮件地址。

  2. 如果用户想要更改他们的主要电子邮件地址,我们将交换“主要”和“非主要”项目中的 email 值。 (现在 DynamoDB 支持transactions,这样做会比以前更安全!)

  3. 如果我们需要删除用户,我们必须删除该userId 的所有项目。如果我们需要合并两个用户,那么我们必须合并该 userId 的所有项目。

  4. 相同的方法(具有相同 userId 但排序键不同的新项目)可用于其他需要为 Query-able 的 1-user-has-many-values 数据

这是一个好方法吗?有没有更好的办法?

【问题讨论】:

  • 贾斯汀,为了搜索属性,我强烈建议不要使用 DynamoDB。我不是说,你可以做到这一点。但是,如果您选择这个根目录,我看到一些问题最终会出现在您的道路上。
  • @mango - 你预见到什么问题?
  • 我不小心在评论中写下了我的答案。我在答案部分添加了详细答案。我希望这会有所帮助。

标签: amazon-web-services amazon-dynamodb dynamodb-queries


【解决方案1】:

贾斯汀,对于搜索属性,我强烈建议不要使用 DynamoDB。我不是说,你不能做到这一点。但是,如果您选择此根,我发现一些问题最终会出现在您的道路上。

  1. 在 email-id 上使用排序键将导致为同一用户创建重复记录,即如果用户注册了 5 封电子邮件,这意味着您的表中有 5 条记录具有相同的架构和属性,但 email-id 属性除外。
  2. 如果将来出现新的用例,现在您还想根据其他属性(例如手机号码,假设用户可能有多个手机号码)搜索用户,该怎么办
  3. DynamoDB 有一个 hard limit of the number of secondary indexes,您可以为表创建,即 5。

因此,随着搜索条件用例的增加,此解决方案很容易成为您系统的瓶颈。因此,您的系统可能无法很好地扩展。


据我所知,我可以建议您根据您的需求/预算选择一些选项,以使用数据库组合来解决此问题。

Option 1. DynamoDB 作为主存储,AWS Elasticsearch 作为二级存储[首选]

  1. 在用户注册时将用户记录存储在 DynamoDB 表(我们称之为 UserTable)中。
  2. UserTable 表上启用 DynamoDB 表流。
  3. 构建一个 AWS Lambda 函数,该函数从表的流中读取数据并将记录保存在 AWS Elasticsearch 中。

现在在您的应用程序中,使用 DynamoDB 从 id 获取用户记录。对于所有其他搜索条件(如搜索 emailId、电话号码、邮政编码、位置等),从 AWS Elasticsearch 获取记录。 AWS Elasticsearch 默认为您记录的所有属性编制索引,因此您可以在延迟毫秒内搜索任何字段。

Option 2. 使用 AWS Aurora [不太喜欢的解决方案]

如果您的应用程序具有数据相关的关系用例,您可以考虑使用此选项。顺便说一句,Aurora 是一个 SQL 数据库。 由于这是一种关系存储,您可以选择将记录组织在多个表中,并根据这些表的主键连接它们。



我建议第一个选项为:

  1. DynamoDB 将为您的应用程序提供持久、高可用性、低延迟的主存储。
  2. AWS Elasticsearch 将充当辅助存储,它也是持久、可扩展和低延迟的存储。
  3. 使用 AWS Elasticsearch,您可以在您的表上运行任何搜索查询。您还可以对数据进行分析。 Kibana UI 是开箱即用的,您可以使用它在仪表板上绘制分析数据,例如(用户增长趋势如何,有多少用户属于特定位置,基于城市/州/国家的用户分布等)
  4. 借助 DynamoDB 流和 AWS Lambda,您将近乎实时地同步这两个数据库 [在几毫秒内]
  5. 您的应用程序将具有可扩展性,并且可以进一步增强搜索功能以对多级属性进行过滤。 [一个这样的例子:搜索属于给定城市的所有用户]

话虽如此,现在我将由您决定。 ?

【讨论】:

  • 如果您已经承诺将 DynamoDB 用作主数据存储并使用 Elastic 作为辅助数据存储,请尝试 Rockset (rockset.com/blog/running-fast-sql-on-dynamodb-tables)。与弹性相比,主要优势在于您可以获得完整的 SQL 和自动缩放/无服务器,就像 lambda 一样。 Rockset 不是事务性的,不支持删除/修改数据,但如果您只想快速查询,Rockset 将支持这一点。
猜你喜欢
  • 1970-01-01
  • 2021-02-19
  • 2013-10-08
  • 2021-12-27
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多