性能效率的最佳做法

本文介绍性能效率的最佳做法,内容按照以下部分中列出的体系结构原则进行组织。

1.垂直缩放、水平缩放和线性可伸缩性

在讨论最佳做法之前,让我们先了解有关分布式计算的几个概念:水平缩放、垂直缩放和线性可伸缩性。

  • 垂直缩放:通过在单台计算机上添加或删除资源(通常是 CPU、内存或 GPU)来垂直缩放。 这通常意味着停止工作负载,将其移动到更大的计算机上,然后重新启动它。 垂直缩放存在限制:可能没有更大的计算机,或者下一个更大计算机的价格可能令人望而却步。

  • 水平缩放:通过在分布式系统中添加或删除节点来水平缩放。 达到垂直缩放限制时,解决方案是水平缩放:分布式计算使用具有多个计算机(称为群集)的系统来运行工作负载。 重要的是要理解,要做到这一点,工作负载必须为并行执行做好准备,正如 Databricks Data Intelligence 平台、Apache Spark 和 Photon 引擎支持的那样。 这使得可将多台便宜的计算机组合成一个更大的计算系统。 需要更多计算资源时,水平缩放会向群集添加更多节点,并删除不再需要的节点。 虽然技术上没有限制(Spark 引擎负责负载均衡的复杂部分),但大量节点确实增加了管理的复杂性。

  • 线性可伸缩性:是指在向系统添加更多资源时,吞吐量和已用资源之间的关系是线性的。 仅当并行任务是独立的时,才可以实现线性缩放。 否则,群集中的另一组节点上需要有一组节点的中间结果才能进行进一步的计算。 节点之间的这种数据交换涉及到通过网络将结果从一组节点传输到另一组节点,这需要相当长的时间。 一般而言,分布式计算在管理数据的分布和交换方面会产生一些开销。 因此,可以在单个节点上分析的小型数据集工作负载在分布式系统上运行时可能反而更慢。 Databricks Data Intelligence 平台提供灵活计算(单节点和分布式)来满足工作负载的独特需求。

2. 根据性能要求设计工作负载

了解数据引入和访问模式

从性能的角度看,数据访问模式(例如“聚合与点访问”或“扫描与搜索”)根据数据大小而有不同的行为。 较大文件对于扫描查询更有效,而较小文件更适合搜索,因为需要读取的数据更少就能找到特定的行。

对于引入模式,通常会使用 DML 语句。 当数据聚类时,DML 语句的性能最高,你可以简单地隔离数据部分。 在引入期间保持数据聚类和可隔离性非常重要:考虑保留自然时间排序顺序,并将尽可能多的筛选器应用于引入目标表。 对于仅追加和覆盖引入工作负载,无需考虑太多,因为这是一个相对便宜的操作。

引入和访问模式通常指向明显的数据布局和聚类。 如果不是,请确定什么对你的业务更重要,并专注于如何更好地实现这一目标。

在并行计算有利的情况下使用并行计算

价值实现时间是处理数据时的一个重要维度。 虽然许多用例可以在单个计算机上轻松实现(小型数据、很少和简单的计算步骤),但通常有用例需要处理大型数据集,由于复杂的算法而运行很长时间,或者需要重复 100 和 1000 次。

Databricks 平台的群集环境是高效分配这些工作负载的极佳环境。 它自动跨群集的所有节点并行化 SQL 查询,并提供适用于 PythonScala 的库来实现相同的目的。 在后台,Apache Spark 和 Photon 引擎会分析查询,确定并行执行的最佳方式,并以弹性方式管理分布式执行。

与批处理任务一样,结构化流式处理在整个群集中分配流式处理作业以提供最佳性能。

使用并行计算的最简单方式之一是增量实时表。 在 SQL 或 Python 中声明作业的任务和依赖项,然后增量实时表将处理执行计划、高效基础结构设置、作业执行和监视工作。

Pandas 是数据科学家常用的一个 Python 包,可为 Python 编程语言提供易于使用的数据结构和数据分析工具。 但是,Pandas 不会横向扩展到大数据。 Spark 上的 Pandas API 可提供在 Apache Spark 上运行的、与 Pandas 等效的 API,从而填补这一空白。

此外,该平台还在标准机器学习库 MLlib 中提供了并行化机器学习算法。 它支持开箱即用的多 GPU 用法。 还可以使用 Horovod RunnerDeepSpeed 分发服务器TorchDistributor 将深度学习并行化。

分析整个执行链

大多数管道或消耗模式都涉及一系列系统。 例如,使用 BI 工具时,性能受多种因素影响:

  • BI 工具本身。
  • 连接 BI 工具和 SQL 引擎的连接器。
  • BI 工具向其发送查询的 SQL 引擎。

为了获得一流的性能,必须考虑并选择/优化整个链来获得最佳性能。

优先使用较大的群集

规划较大的群集,尤其是当工作负载线性缩放时。 在这种情况下,对工作负载使用大型群集并不比使用较小群集更昂贵。 而速度却更快。 关键在于根据工作负载的持续时间租用群集。 因此,如果运行两个工作器群集一小时,则需要为这些工作器支付整整一个小时的费用。 同样,如果你运行由四个工作器构成的群集半小时(此时线性可伸缩性会发挥作用),那么成本是相同的。 如果成本是非常灵活 SLA 的主要驱动因素,则自动缩放群集通常是最便宜的,但不一定是最快的。

注意

无服务器计算不需要首选大型群集,因为它会自动管理群集。

使用本机 Spark 操作

用户定义的函数 (UDF) 是扩展 Spark SQL 功能的好方法。 但是,如果存在本机函数,请不要使用 Python 或 Scala UDF:

原因:

  • 要在 Python 和 Spark 之间传输数据,需要使用序列化。 这会显著降低查询速度。
  • 增加了实现和测试平台中已存在的功能的工作。

如果缺少本机函数并且应将本机函数作为 Python UDF 实现,请使用 Pandas UDFApache Arrow 确保数据在 Spark 和 Python 之间高效地来回移动。

使用本机平台引擎

Photon 是 Azure Databricks 上的引擎,可直接在数据湖上以低成本提供快速查询性能 - 从数据引入、ETL、流、数据科学到交互式查询。 Photon 与 Apache Spark API 兼容,因此只需打开就能使用 – 无需更改代码,且没有局限性。

Photon 是高性能运行时的一部分,可更快运行现有 SQL 和数据帧 API 调用,从而降低每个工作负载的总成本。 Databricks SQL 仓库中默认使用 Photon。

了解硬件和工作负载类型

并非所有云 VM 都是相同创建的。 云提供商提供的各种计算机系列都是不同的,需要重点考虑这一点。 有明显的差别 - RAM 和核心 – 还有更细微的差别 – 处理器类型和代次、网络带宽保证,以及本地高速存储、本地磁盘与远程磁盘。 “现货”市场也存在差异。 在为工作负载确定最佳 VM 类型之前,应了解这些差异。

使用缓存

缓存将频繁访问的数据存储在更快的介质中,与访问原始数据源相比缩短了检索数据所需的时间。 这会降低延迟并加快响应时间,从而显着提高应用程序的整体性能和用户体验。 通过最大程度地减少对原始数据源的请求数,缓存有助于降低网络流量和数据传输成本。 这种效率提升对于依赖外部 API 或按使用付费数据库的应用程序尤其有利。 它可以帮助在整个系统中更均匀地分配负载,从而防止出现瓶颈和潜在的停机时间。

Azure Databricks 中提供了几种类型的缓存。 以下是每个类型的特征:

  • 使用磁盘缓存

    磁盘缓存(以前称为“增量缓存”)将远程数据的副本存储在虚拟机的本地磁盘(例如 SSD)上。 它可以提高各种查询的性能,但不能用于存储任意子查询的结果。 磁盘缓存会自动检测创建或删除数据文件的时间,并相应地更新其内容。 建议的(也是最简单的)磁盘缓存使用方法是在配置群集时选择使用 SSD 卷的工作器类型。 为磁盘缓存启用并配置此类工作器。

  • 避免 Spark 缓存

    Spark 缓存(使用 .persist().unpersist())可以存储任何子查询数据的结果,以及以非 Parquet 格式(例如 CSV、JSON 和 ORC)存储的数据。 但是,如果在查询中的错误位置使用,则可能会消耗所有内存,甚至大幅降低查询速度。 根据经验,除非你确切知道会有什么影响,否则请避免使用 Spark 缓存

  • 查询结果缓存

    按群集缓存通过 SQL 仓库进行的所有查询的查询结果。 若要从查询结果缓存受益,请将重点放在确定性查询上,例如不要使用 = NOW() 之类的谓词。 如果查询是确定性的,并且基础数据是 Delta 格式且未更改,则 SQL 仓库将直接从查询结果缓存中返回结果。

  • Databricks SQL UI 缓存

    Databricks SQL UI 中按用户缓存所有查询和旧版仪表板结果。

使用压缩

Azure Databricks 上的 Delta Lake 可提高表中读取查询的速度。 一种方法是将小文件合并成较大的文件。 通过运行 OPTIMIZE 命令来触发压缩。 请参阅优化数据文件布局

Delta Lake 提供了用于自动配置写入和 OPTIMIZE 操作的目标文件大小的选项。 Databricks 会自动优化其中的许多设置,并启用通过找出适当文件大小来自动提高表性能的功能:

  • 自动压缩合并 Delta 表分区中的小文件,自动减少小文件存在的问题。 自动压缩发生在向表进行写入的操作成功后,在执行了写入操作的群集上同步运行。 自动压缩仅压缩以前尚未压缩过的文件。
  • 优化写入在写入数据时改善文件大小,并有利于后续对表的读取。 优化写入对已分区表的效果最好,因为它们可以减少写入每个分区的小文件数。

有关更多详细信息,请参阅配置 Delta Lake 以控制数据文件大小

使用数据跳过

数据跳过可以通过跳过不符合查询条件的数据来显着提高查询性能。 这样可以减少需要读取和处理的数据量,从而加快查询执行时间。

为实现此目的,将数据写入 Delta 表时,会自动收集数据跳过信息(默认情况下,Azure Databricks 上的 Delta Lake 会收集表架构中定义的前 32 列的统计信息)。 Azure Databricks 上的 Delta Lake 会在查询时使用此信息(最小值和最大值)来提供更快的查询。 请参阅 Delta Lake 的数据跳过

为获得最佳结果,请使用 Z 排序,这是一种将相关信息共置在同一组文件中的技术。 Azure Databricks 上的 Delta Lake 数据跳过算法会自动使用此共置技术。 此行为显著减少了 Delta Lake 必须读取的数据量。

或者,使用较新的 Liquid 聚类分析,这简化了数据布局决策并优化了查询性能。 随着时间的推移,它将替换分区和 Z 排序。 Databricks 建议对所有新 Delta 表使用 liquid 聚类分析。 Liquid 聚类分析提供了在不重写现有数据的情况下重新定义聚类分析键的灵活性,从而使数据布局能够随着分析需求和时间推移而演变。 Databricks 建议对所有新 Delta 表使用 liquid 聚类分析。

具有以下特征的表受益于 liquid 聚类分析:

  • 表按具有高基数的列进行筛选。
  • 表的数据分布明显倾斜。
  • 表增长迅速且需要维护和优化工作。
  • 表具有并发写入要求。
  • 表的访问模式随时间变化。
  • 在表中,典型分区键可能使表具有过多或过少的分区。

有关更多详细信息和技术,请参阅优化 Databricks、Spark 和 Delta Lake 工作负载的综合指南

避免过度分区

过去,分区是最常见的数据跳过方式。 但是,分区是静态的,并且本身呈现为文件系统层次结构。 当访问模式随时间变化时,没有简单的方法来更改分区。 通常,分区会导致过度分区 - 换言之,有太多的分区包含太小的文件,导致查询性能不佳。

Databricks 建议不要对大小低于 1 TB 的表进行分区,并且如果希望每个分区中的数据至少为 1 GB,则仅按列进行分区。

同时,比分区更好的选择是 Z 排序或较新的 Liquid 聚类分析(见上文)。

优化联接性能

  • 考虑范围联接优化。

    当使用间隔中的点或间隔重叠条件联接两个关系时,将会发生范围联接。 Databricks Runtime 中的范围联接优化支持可以在查询性能方面带来数量级的改进,但需要仔细地进行手动优化。

  • 使用自适应查询执行。

    自适应查询执行 (AQE) 是在查询执行期间发生的查询重新优化。 它有 4 个主要功能:

    • 将排序合并联接动态更改为广播哈希联接。
    • 随机交换后动态合并分区。
    • 在排序合并联接和随机哈希联接中动态处理倾斜。
    • 动态检测并传播空关系。

    建议保持 AQE 启用。 可以单独配置不同的功能。

有关更多详细信息,请参阅优化 Databricks、Spark 和 Delta Lake 工作负载的综合指南

运行 analyze table 以收集表统计信息

ANALYZE TABLE 语句收集指定架构中表的统计信息。 查询优化器使用这些统计信息生成最佳查询计划,从而选择正确的联接类型、在哈希联接中选择正确的生成端,或者在多路联接中校准联接顺序。

若要正确利用这些查询优化,需要定期执行 ANALYZE TABLE 命令(最好是每天执行一次,或者当数据变化超过 10% 时执行,以先发生的情况为准)。

3. 在开发范围内运行性能测试

基于代表生产数据的数据进行测试

基于生产数据(只读)或类似数据运行性能测试。 使用相似数据时,数量、文件布局和数据倾斜等特征应该与生产数据相似,因为这对性能有重大影响。

考虑预热资源

与查询和数据格式无关,群集上的第一个查询始终比后续查询要慢。 这是因为所有不同的子系统都在启动和读取所需的所有数据。 预热对性能测试结果的影响很大:

  • 预热群集:群集资源需要在多个层上初始化。 可以预热群集:Databricks 池是一组空闲的、随时可用的实例。 使用这些空闲实例创建群集节点后,可以减少群集启动和自动缩放的时间。
  • 预热缓存:当缓存是设置的一部分时,首次运行可确保数据位于缓存中,从而加快后续作业的速度。 可以通过运行特定查询初始化缓存(例如在群集重启后)来预热缓存。 这可以显著提高前几个查询的性能。

因此,若要了解不同方案的行为,请测试首次执行(使用和不使用预热)和后续执行的性能。

识别瓶颈

瓶颈是工作负载中随着生产中负载的增加而降低整体性能的方面。 在设计时识别瓶颈并针对更高的工作负载进行测试有助于保持生产环境中工作负载的稳定性。

4. 监视性能

监视查询性能

监视查询性能可帮助你了解不同查询如何使用资源。 可以识别运行缓慢的查询,从而确定系统中的性能瓶颈。 还可以识别正在消耗大量系统资源,可能导致不稳定或停机的查询。 此信息可帮助你优化资源分配、减少浪费并确保有效使用资源。

Databricks Data Intelligence 平台具有各种监视功能(请参阅卓越运营 - 设置监视、警报和日志记录),其中一些功能可用于性能监视:

  • 查询配置文件:使用查询配置文件功能排查查询执行期间的性能瓶颈问题。 它提供了每个查询任务和相关指标的可视化,例如花费的时间、处理的行数和使用的内存。
  • SQL 仓库监视:通过查看实时统计信息、峰值查询计数图表、正在运行的群集图表和查询历史记录表来监视 SQL 仓库

监视流式处理工作负载

流式监视使你能够分析数据并检测问题,从而实时了解系统的性能和行为。 通过分析流式处理数据,可以识别趋势、模式和优化机会。 这可帮助你微调系统、提高资源利用率并降低成本。

对于流式处理查询,请使用 Spark UI 中的内置结构化流式处理监视,或者使用 Apache Spark 流式处理查询侦听器接口将指标推送到外部服务。

监视作业性能

作业监视有助于识别和解决 Databricks 作业中的问题,例如故障、延迟或性能瓶颈。 作业监视提供对作业性能的见解,使你能够优化资源利用率、减少占用并提高整体效率。