许多开发团队都使用 DynamoDB 来构建事件驱动架构和用户友好、性能卓越的大规模应用程序。作为运营数据库,DynamoDB 针对实时事务进行了优化,即使部署在多个地理位置也是如此。但是,它无法为搜索和分析访问模式提供强大的性能。
虽然 DynamoDB 等 NoSQL 数据库通常具有出色的扩展特性,但它们仅支持一组有限的专注于在线事务处理的操作。如果不严重依赖高效的索引策略,就很难搜索、过滤、聚合和连接数据。
DynamoDB 根据每个项目中存在的用户指定的分区键字段,将数据分区到大量节点上,从而实现数据在后台的存储。此用户指定的分区键可以选择性地与排序键组合以表示主键。主键充当索引,使查询操作变得成本低廉。查询操作可以对分区键执行相等性比较 (=),对排序键执行比较操作 (>、<、=、BETWEEN)(如果指定)。
执行上述方案未涵盖的分析查询需要使用扫描操作,该操作通常通过并行扫描整个 DynamoDB 表来执行。这些扫描在读取吞吐量方面可能很慢且成本高昂,因为它们需要完全读取整个表。当表大小增加时,扫描速度也会变慢,因为需要扫描更多数据才能产生结果。如果我们想支持分析查询而又不遇到过高的扫描成本,我们可以利用二级索引,我们将在下文讨论。
在 DynamoDB 中,二级索引通常用于通过索引经常查询的字段来提高应用程序性能。二级索引上的查询操作还可用于通过具有明确定义要求的分析查询来支持特定功能。
二级索引包括在我们要查询的字段上创建分区键和可选排序键。二级索引有两种类型:
本地二级索引 (LSI):LSI 扩展单个分区的哈希和范围键属性。
全局二级索引 (GSI):GSI 是应用于整个表而不是单个分区的索引。
然而,正如Nike 发现的那样,在 DynamoDB 中过度使用 GSI 可能会付出高昂代价。除非仅用于非常简单的点查找或小范围扫描,否则 DynamoDB 中的分析可能会导致过度使用二级索引并产生高昂成本。
使用索引时,预置容量的成本会迅速增加,因为对基表的所有更新也必须在相应的 GSI 中进行。事实上,AWS 建议全局二级索引的预置写入容量应等于或大于基表的写入容量,以避免限制对基表的写入并削弱应用程序。预置写入容量的成本会随着配置的 GSI 数量线性增长,因此使用许多 GSI 来支持许多访问模式的成本过高。
DynamoDB 的设计也不太适合索引嵌套结构中的数据,包括数组和对象。在索引数据之前,用户需要对数据进行非规范化,使嵌套对象和数组扁平化。这可能会大大增加写入次数和相关成本。
有关使用 DynamoDB 二级索引进行分析的更详细信息,请参阅我们的博客DynamoDB 上的分析二级索引。
最重要的是,对于分析用例,您可以通过将 DynamoDB 表与充当外部二级索引的其他工具或服务同步来获得显著的性能和成本优势,从而高效运行复杂的分析。
在我们的数据上构建二级索引的一种方法是将 DynamoDB 与 Elasticsearch 结合使用。基于云的 Elasticsearch(例如 Elastic Cloud 或 Amazon OpenSearch Service)可用于根据索引的大小、复制和其他要求来配置和配置节点。托管集群需要一些操作来升级、保护和保持性能,但比在 EC2 实例上完全自行运行要少。
由于使用Amazon DynamoDB 的 Logstash 插件的方法不受支持且设置起来相当困难,因此我们可以使用 DynamoDB Streams 和 AWS Lambda 函数将写入从 DynamoDB 流式传输到 Elasticsearch。这种方法要求我们执行两个单独的步骤:
我们必须使用正确的权限编写和连接这两个 lambda 函数,以确保我们不会错过任何对表的写入。设置好它们并进行必要的监控后,我们可以从 DynamoDB 接收 Elasticsearch 中的文档,并使用 Elasticsearch 对数据运行分析查询。
这种方法的优点是 Elasticsearch 支持全文索引和多种类型的分析查询。Elasticsearch 支持各种语言的客户端和 Kibana 等可视化工具,可帮助快速构建仪表板。正确配置集群后,可以调整查询延迟,以便对流入 Elasticsearch 的数据进行快速分析查询。
缺点包括解决方案的设置和维护成本可能很高。即使是托管的 Elasticsearch 也需要处理底层实例的复制、重新分片、索引增长和性能调整。
Elasticsearch 具有紧密耦合的架构,不分离计算和存储。这意味着资源经常被过度配置,因为它们无法独立扩展。此外,多个工作负载(例如读取和写入)将争夺相同的计算资源。
Elasticsearch 也无法高效处理更新。更新任何字段都会触发对整个文档的重新索引。Elasticsearch 文档是不可变的,因此任何更新都需要对新文档进行索引,并将旧版本标记为已删除。这会导致额外的计算和 I/O 消耗,即使对未更改的字段进行重新索引,并在更新时写入整个文档。
由于 lambda 在看到 DynamoDB 流中的更新时会触发,因此它们可能会因冷启动而出现延迟峰值。设置需要指标和监控,以确保它正确处理来自 DynamoDB 流的事件并能够写入 Elasticsearch。
从功能上讲,在分析查询方面, Elasticsearch 缺乏对连接的支持,而连接对于涉及多个索引的复杂分析查询非常有用。Elasticsearch 用户通常必须对数据进行非规范化、执行应用程序端连接或使用嵌套对象或父子关系来绕过此限制。
优点
缺点
在使用 Kibana 对 DynamoDB 和仪表板中的数据实施全文搜索时,此方法效果很好。但是,在生产中调整和维护 Elasticsearch 集群所需的操作、其资源使用效率低下以及缺乏连接功能可能会带来挑战。
Rockset是一个完全托管的搜索和分析数据库,主要用于支持具有高 QPS 要求的实时应用程序。它通常用作 OLTP 数据库数据的外部二级索引。
Rockset 具有内置 DynamoDB 连接器,可用于在 DynamoDB 和 Rockset 之间保持数据同步。我们可以指定要同步内容的 DynamoDB 表以及索引该表的 Rockset 集合。Rockset 在完整快照中索引 DynamoDB 表的内容,然后在发生新更改时同步它们。Rockset 集合的内容始终与 DynamoDB 源同步;在稳定状态下,间隔不超过几秒钟。
Rockset 通过监控流的状态并提供对 DynamoDB 流变化的可见性来自动管理 DynamoDB 表和 Rockset 集合之间的数据完整性和一致性。
无需架构定义,Rockset 集合可以在添加/删除字段时,或者在 DynamoDB 中数据本身的结构/类型发生变化时自动适应。这是通过强动态类型和智能架构实现的,无需任何额外的 ETL。
我们从 DynamoDB 获得的 Rockset 集合支持使用 SQL 进行查询,开发人员可以轻松使用,无需学习特定领域的语言。它还可用于通过 REST API 或使用多种编程语言的客户端库向应用程序提供查询。Rockset 支持的 ANSI SQL 超集可以在深度嵌套的 JSON 数组和对象上原生运行,并利用自动在所有字段上构建的索引,即使在复杂的分析查询中也能获得毫秒级的延迟。
Rockset 率先采用了计算分离技术,允许在不同的计算单元中隔离工作负载,同时共享相同的底层实时数据。这在支持同时提取和查询或在同一数据集上执行多个应用程序时为用户提供了更高的资源效率。
此外,Rockset 还负责安全性、数据加密和基于角色的访问控制,以管理对数据的访问。Rockset 用户可以利用我们在 Rockset 中设置的摄取转换来修改到达集合的数据,从而避免 ETL 的需要。用户还可以选择通过设置保留策略来自动清除旧数据,从而管理数据的生命周期。数据摄取和查询服务都是自动管理的,这让我们可以专注于构建和部署实时仪表板和应用程序,而无需进行基础设施管理和运营。
Rockset 与 DynamoDB 同步尤其相关,它支持现场字段级更新,从而避免昂贵的重新索引。从提取、查询和效率方面比较 Rockset 和 Elasticsearch,以选择适合该工作的工具。
我们可以使用 Rockset 对DynamoDB 中的数据进行实时分析,而无需担心任何操作、扩展或维护问题。这可以显著加快实时应用程序的开发速度。如果您想使用 Rockset 在 DynamoDB 数据上构建应用程序,您可以在此处免费开始。