性能效率支柱 - AWS 规范性指导

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

性能效率支柱

Well-Architect AWS ed Framework 的性能效率支柱侧重于如何在摄取或查询数据时优化性能。性能优化是一个循序渐进的持续过程,包括以下内容:

  • 确认业务需求

  • 衡量工作负载性能

  • 识别性能不佳的组件

  • 调整组件以满足您的业务需求

性能效率支柱提供了特定于用例的指南,可以帮助确定要使用的正确图表数据模型和查询语言。它还包括在向 Amazon Neptune 中摄取数据和使用数据时应遵循的最佳实践。

绩效效率支柱侧重于以下关键领域:

  • 图形建模

  • 查询优化

  • 正确调整集群大小

  • 写入优化

了解图形建模

了解标签属性图 (LPG) 和资源描述框架 (RDF) 模型之间的区别。在大多数情况下,这是一个偏好的问题。但是,在一些用例中,一种模型比另一种模型更适合。如果您需要了解连接图表中两个节点的路径,请选择 LPG。如果要在 Neptune 集群或其他图形三重存储之间联合数据,请选择 RDF。

如果您正在构建软件即服务 (SaaS) 应用程序或需要多租户的应用程序,请考虑在数据模型中纳入租户的逻辑分离,而不是为每个集群设置一个租户。要实现这种类型的设计,您可以使用 SPARQL 命名图形和标签策略,例如在标签前添加客户标识符或添加代表租户标识符的属性键值对。确保您的客户端层注入这些值以保持逻辑分离。

查询的性能取决于在处理查询时需要评估的图形对象(节点、边、属性)的数量。因此,图形模型可能会对应用程序的性能产生重大影响。尽可能使用精细标签,并仅存储实现路径确定或筛选所需的属性。要获得更高的性能,可以考虑预先计算图形的各个部分,例如创建汇总节点或连接公共路径的更直接的边。

尽量避免在具有相同标签的边数异常多的节点之间导航。此类节点通常有数千条边(其中大多数节点的边数以十为单位)。结果是计算和数据复杂度大大提高。在某些查询模式中,这些节点可能不会出现问题,但我们建议您以不同的方式对数据进行建模以避免这种情况,特别是当您将作为中间步骤在节点上导航时。您可以使用慢速查询日志来帮助识别在这些节点上导航的查询。您可能会观察到比平均查询模式更高的延迟和数据访问指标,尤其是在使用调试模式的情况下。

如果您的用例支持,请 IDs 为节点和边使用确定性节点,而不是使用 Neptune 为其分配随机 GUID 值。 IDs通过 ID 访问节点是最有效的方法。

优化查询

OpenCypher 和 Gremlin 语言可以在液化石油气模型上互换使用。如果性能是头等大事,可以考虑交替使用这两种语言,因为对于特定的查询模式,一种语言的性能可能比另一种更好。

Neptune 正在转换为其替代查询引擎 (DFE)。OpenCypher 仅在 DFE 上运行,但可以选择使用查询注释将 Gremlin 和 SPARQL 查询设置为在 DFE 上运行。考虑在激活 DFE 的情况下测试您的查询,并比较不使用 DFE 时的查询模式性能。

Neptune 针对事务型查询进行了优化,这些查询从单个节点或一组节点开始,然后从那里扇出,而不是评估整个图表的分析查询。对于您的分析查询工作负载,可以考虑使用适用于 Pandas 的 AWS 开发工具包,或者将 ne ptune-ex port 与或 Amazon AWS GlueEMR 结合使用。

要识别模型和查询中的效率低下和瓶颈,请使用每种查询语言的profileexplain APIs 来获取查询计划和查询指标的详细解释。有关更多信息,请参阅 Gremlin 个人资料OpenCypher 解释和 SPARQL 解释

了解您的查询模式。如果图形中不同边的数量变大,则默认的 Neptune 访问策略可能会变得效率低下。以下查询可能会变得非常低效:

  • 未给出边缘标签时跨边向后导航的查询。

  • 在内部使用相同模式的子句,例如.both()在 Gremlin 中,或者使用任何语言删除节点的子句(这需要在不了解标签的情况下删除传入的边缘)。

  • 在不指定属性标签的情况下访问属性值的查询。这些查询可能会变得非常低效。如果这符合您的使用模式,请考虑启用 OSGP 索引(对象、主题、图表、谓词)。

使用慢查询日志记录来识别慢速查询。查询速度慢可能是由未优化的查询计划或不必要的大量索引查找造成的,这可能会增加 I/O 成本。Neptune 解释和分析 GremlinSPARQLOpenCypher 的端点可以帮助你了解为什么这些查询很慢。原因可能包括以下几点:

  • 与图中的平均节点相比,边数异常多的节点(例如,数千条和十条)会增加计算复杂性,从而延长延迟并增加资源消耗。确定这些节点的建模是否正确,或者是否可以改进访问模式以减少必须遍历的边数。

  • 未优化的查询将包含一条警告,提示特定步骤未经过优化。重写这些查询以使用优化的步骤可能会提高性能。

  • 冗余过滤器可能会导致不必要的索引查找。同样,冗余模式可能会导致重复的索引查找,可以通过改进查询来优化(参见配置文件输出Index Operations - Duplication ratio中的)。

  • 某些语言(例如 Gremlin)没有强键入的数值,而是使用类型提升。例如,如果值为 55,Neptune 会查找整数、多头、浮点数和其他等同于 55 的数值类型的值。这会导致额外的操作。如果您事先知道自己的类型匹配,则可以使用查询提示来避免这种情况。

  • 您的图形模型会极大地影响性能。考虑通过使用更精细的标签或预先计算多跳线性路径的快捷方式来减少需要评估的对象数量。

如果仅靠查询优化无法满足性能要求,请考虑在 Neptune 中使用各种缓存技术来满足这些要求。

大小合适的集群

根据您的并发和吞吐量要求调整集群规模。集群中每个实例可以处理的并发查询数量等于该实例上虚拟 CPUs (vCPUs) 数量的两倍。在所有工作线程都被占用时到达的其他查询将放入服务器端队列中。当工作线程可用时,将在 first-in-first-out (FIFO) 基础上处理这些查询。A MainRequestQueuePendingRequests mazon CloudWatch 指标显示每个实例的当前队列深度。如果此值经常大于零,请考虑选择一个具有更多 v 的实例CPUs。 如果队列深度超过 8,192,Neptune 将返回ThrottlingException错误。

每个实例的大约 65% 的 RAM 是为缓冲区缓存预留的。缓冲区缓存保存数据的工作数据集(不是整个图表;只是正在查询的数据)。要确定从缓冲区缓存而不是存储中提取的数据的百分比,请监控该 CloudWatch 指标BufferCacheHitRatio。如果该指标经常降至99.9%以下,请考虑尝试使用具有更多内存的实例,以确定它能否降低延迟和I/O成本。

只读副本的大小不必与您的写入器实例相同。但是,繁重的写入工作负载可能会导致较小的副本落后并重新启动,因为它们无法跟上复制的速度。因此,我们建议使副本等于或大于写入器实例。

对只读副本使用 auto-scaling 时,请记住,将新的只读副本联机可能需要 15 分钟。当客户端流量快速但可预测地增加时,可以考虑使用定时扩展来设置更高的只读副本的最小数量,以考虑该初始化时间。

无服务器实例支持多种不同的用例和工作负载。在以下情况下,可以考虑使用无服务器而不是预配置实例:

  • 您的工作量在一天中经常波动。

  • 您创建了一个新应用程序,但不确定工作负载的大小。

  • 你正在进行开发和测试。

值得注意的是,按每 GB RAM 的美元计算,无服务器实例比同等的预配置实例更昂贵。每个无服务器实例由 2 GB 的 RAM 以及关联的 vCPU 和网络组成。在您的选项之间进行成本分析,以避免意外账单。通常,只有当您的工作量非常繁重且每天只有几个小时,而一天中的其余时间几乎为零,或者您的工作量在一天中波动很大,您才能通过无服务器实现成本节约。

优化写入

要优化写入,请考虑以下几点:

  • Nep tune 批量加载器是初始加载数据库或追加到现有数据的最佳方式。Neptune 加载器不是事务性的,也无法删除数据,因此如果您有这些要求,请不要使用它。

  • 可以使用支持的查询语言进行事务更新。要优化写入 I/O 操作,请在每次提交时以 50-100 个对象为单位批量写入数据。对象是 LPG 中节点或边上的节点、边缘或属性,或者是 RDF 中的三重存储或四边形。

  • 对于每个连接,所有 Neptune 写入操作都是单线程的。向 Neptune 发送大量数据时,可以考虑使用多个并行连接,每个并行连接都在写入数据。当您选择 Neptune 预配置的实例时,实例大小与数字 v 相关联。CPUs Neptune 为实例上的每个 vCPU 创建两个数据库线程,因此在测试最佳并行化CPUs 时,从 v 数的两倍开始。  无服务器实例以大约每 4 NCUs 个 1 的速率缩放 v CPUs 的数量。

  • 即使任何时候只有一个连接ConcurrentModificationExceptions在写入数据,也要做好所有写入过程的规划和高效处理。设计您的客户端,确保ConcurrentModificationExceptions发生时的可靠性。

  • 如果您想删除所有数据,请考虑使用快速重置 API,而不是发出并发删除查询。与前者相比,后者将花费更长的时间,并且会产生大量的 I/O 成本。

  • 如果要删除大部分数据,可以考虑使用 nept une-export 将数据加载到新集群中来导出要保留的数据。然后删除原始集群。