Spark3 新特性之AQE

Spark3的AQE特性通过动态优化,包括自动分区合并、数据倾斜处理和Join策略调整,解决了Spark2.x中数据倾斜和执行效率问题。在运行时,AQE结合统计信息调整逻辑和物理计划,改善了任务执行的时间和资源利用率。对比验证显示,开启AQE显著减少了执行时间,提高了任务性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spark3 AQE

一、 背景

Spark 2.x 在遇到有数据倾斜的任务时,需要人为地去优化任务,比较费时费力;如果任务在Reduce阶段,Reduce Task 数据分布参差不齐,会造成各个excutor节点资源利用率不均衡,影响任务的执行效率;Spark 3新特性AQE极大地优化了以上任务的执行效率。

二、 Spark 为什么需要AQE? (Why)

RBO(Rule Based Optimization,基于规则的优化),它往往基于一些规则和策略实现,如谓词下推、列剪枝,这些规则和策略来源于数据库领域已有的应用经验。RBO实际上算是一种经验主义。

经验主义的弊端就是对待相似的问题和场景都使用同一类套路。Spark 社区正是因为意识到了 RBO 的局限性,因此在 2.x 版本中推出了CBO(Cost Based Optimization,基于成本的优化)。

CBO 是基于数据表的统计信息(如表大小、数据列分布)来选择优化策略。CBO 支持的统计信息很丰富,比如数据表的行数、每列的基数(Cardinality)、空值数、最大值、最小值等。因为有统计数据做支持,所以 CBO 选择的优化策略往往优于 RBO 选择的优化规则。

但是,CBO 也有三个方面的不足:

  • 适用面太窄,CBO 仅支持注册到 Hive Metastore 的数据表,但在其他的应用场景中,数据源往往是存储在分布式文件系统的各类文件,如 Parquet、ORC、CSV 等。

  • 统计信息的搜集效率比较低。对于注册到 Hive Metastore 的数据表,开发者需要调用 ANALYZE TABLE COMPUTE STATISTICS 语句收集统计信息,而各类信息的收集会消耗大量时间。

  • 静态优化,RBO、CBO执行计划一旦制定完成,就会按照该计划坚定不移地执行;如果在运行时数据分布发生动态变化,先前制定的执行计划并不会跟着调整、适配。

基于CBO的执行计划
在这里插入图片描述

  • Spark parses the query and creates the Unresolved Logical Plan 创建Unresolved Logical Plan
    • Validates the syntax of the query. 验证语法
    • Doesn’t validate the semantics meaning column name existence, data types. 不验证语义、字段是否存在、数据类型
  • Analysis: Using the Catalyst, it converts the Unresolved Logical Plan to Resolved Logical Plan a.k.a Logical Plan. 转换为Logical Plan
    • The catalog contains the column names and data types, during this step, it validates the columns mentioned in a query with catalog.
  • Optimization: Converts Logical Plan into Optimized Logical Plan. 转换为 Optimized Logical Plan
  • Planner: Now it creates One or More Physical Plans from an optimized Logical plan. 创建一个或多个Physical Plans
  • Cost Model: In this phase, calculates the cost for each Physical plan and select the Best Physical Plan. CBO择优
  • RDD Generation: RDD’s are generated, this is the final phase of query optimization which generates RDD in Java bytecode.

三、 AQE 到底是什么?(What)

考虑到 RBO 和 CBO 的种种限制,Spark 在 3.0 版本推出了 AQE(Adaptive Query Execution,自适应查询执行)。用一句话来概括,AQE 是 Spark SQL 的一种动态优化机制,在运行时,每当 Shuffle Map 阶段执行完毕,AQE 都会结合这个阶段的统计信息,基于既定的规则动态地调整、修正尚未执行的逻辑计划和物理计划,来完成对原始查询语句的运行时优化

AQE 赖以优化的统计信息与 CBO 不同,这些统计信息并不是关于某张表或是哪个列,而是 Shuffle Map 阶段输出的中间文件。

基于AQE的执行计划
在这里插入图片描述

四、AQE怎么用?(How)

AQE三大特性:自动分区合并 、自动数据倾斜处理、Join 策略调整

4.1 自动分区合并

在 Shuffle 过后,Reduce Task 数据分布参差不齐,AQE 将自动合并过小的数据分区。

那么AQE是如何确定多小的分区需要合并,以及分区合并到多大时停止合并?

对于所有的数据分区,无论大小,AQE 按照分区编号从左到右进行扫描,边扫描边记录分区尺寸,当相邻分区的尺寸之和大于 “推荐尺寸”时,AQE 就把这些扫描过的分区进行合并。然后,继续向右扫描,并采用同样的算法,按照目标尺寸合并剩余分区,直到所有分区都处理完毕。

“推荐尺寸”是由spark.sql.adaptive.advisoryPartitionSizeInBytes设置

配置说明
spark.sql.adaptive.coalescePartitions.enabledWhen true and ‘spark.sql.adaptive.enabled’ is true, Spark will coalesce contiguous shuffle partitions according to the target size (specified by ‘spark.sql.adaptive.advisoryPartitionSizeInBytes’), to avoid too many small tasks.
开启分区自动合并,默认开启
spark.sql.adaptive.advisoryPartitionSizeInBytesThe advisory size in bytes of the shuffle partition during adaptive optimization (when spark.sql.adaptive.enabled is true). It takes effect when Spark coalesces small shuffle partitions or splits skewed shuffle partition.
分区合并后的推荐尺寸,默认为64M
spark.sql.adaptive.coalescePartitions.minPartitionSizeThe minimum size of shuffle partitions after coalescing. This is useful when the adaptively calculated target size is too small during partition coalescing.
可合并分区尺寸大小,默认为1M

假设推荐尺寸为100M,shuffle后每一个分区的大小为70M、30M、80M、90M、10M、20M

按照正常情况(顺序处理),会启动4个reduce task:

第一个处理:70M、30M

第二个处理:80M

第三个处理:90M

第四个处理:10M、20M

spark3.0版本按照上述情况合并之后,各分区数据还是出现了不均衡,从而导致后续计算出现小的数据倾斜

查看spark 3.2官网新增了 spark.sql.adaptive.coalescePartitions.minPartitionSize(合并分区后,最小分区尺寸),如果把该参数设置为和推荐尺寸一致,那是不是只会启动3个 reduce task,3个都处理100M的数据?(个人猜想,不是按照顺序合并,而是会先遍历分区大小,保证合并后的分区大小相近)

You do not need to set a proper shuffle partition number to fit your dataset. Spark can pick the proper shuffle partition number at runtime once you set a large enough initial number of shuffle partitions via spark.sql.adaptive.coalescePartitions.initialPartitionNum configuration. 官方建议:分区数不用设置,spark会自动设置合适的分区。

4.2 自动数据倾斜处理

AQE 自动拆分 Reduce 阶段过大的数据分区,降低单个Reduce Task 的工作负载。

AQE 如何判定数据分区是否倾斜呢?它又是怎么把大分区拆分成多个小分区的?

配置说明
spark.sql.adaptive.skewJoin.enabledWhen true and ‘spark.sql.adaptive.enabled’ is true, Spark dynamically handles skew in shuffled join (sort-merge and shuffled hash) by splitting (and replicating if needed) skewed partitions.
开启AQE自动数据倾斜处理
spark.sql.adaptive.skewJoin.skewedPartitionFactorA partition is considered as skewed if its size is larger than this factor multiplying the median partition size and also larger than ‘spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes’
判定数据分区是否倾斜,默认值为5
spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytesA partition is considered as skewed if its size in bytes is larger than this threshold and also larger than ‘spark.sql.adaptive.skewJoin.skewedPartitionFactor’ multiplying the median partition size. Ideally this config should be set larger than ‘spark.sql.adaptive.advisoryPartitionSizeInBytes’.
判定数据分区是否倾斜,默认值为256M

判定倾斜分区:大于 median partition size * spark.sql.adaptive.skewJoin.skewedPartitionFactor 且 大于 spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes

假设数据表 A 有 3 个分区,分区大小分别是80MB、100MB 和 512MB。这些分区按大小个排序后的中位数是 100MB,因为

skewedPartitionFactor 的默认值是 5 ,skewedPartitionThresholdInBytes默认值是256M,512M大于 100MB * 5 = 500MB且大于256M 的分区被判定为倾斜分区。

拆分倾斜分区:上述例子512M分区会被拆分 512/256 =2个分区

4.3 Join 策略调整

如果某张表在过滤之后,尺寸小于广播变量阈值,这张表参与的数据关联就会从 Shuffle Sort Merge Join 降级(Demote)为执行效率更高的 Broadcast Hash Join。

Join 策略调整指的就是 Spark SQL在运行时动态地将原本的 Shuffle Join 策略,调整为执行更加高效的 Broadcast Join。

具体来说,每当 DAG 中的 Map 阶段执行完毕,Spark SQL 就会结合 Shuffle 中间文件的统计信息,重新计算 Reduce 阶段数据表的存储大小。如果发现基表尺寸小于广播阈值, 那么 Spark SQL 就把下一阶段的 Shuffle Join 调整为 Broadcast Join。

Broadcast Join 以广播的方式将小表的全量数据分发到集群中所有的 Executors,大表的数据就可以与小表数据在Process local级别进行关联操作。本地性级别有 4 种:Process local < Node local < Rack local < Any。

配置说明
spark.sql.adaptive.autoBroadcastJoinThresholdConfigures the maximum size in bytes for a table that will be broadcast to all worker nodes when performing a join. By setting this value to -1 broadcasting can be disabled. The default value is same with spark.sql.autoBroadcastJoinThreshold. Note that, this config is used only in adaptive framework.
可广播的表尺寸阈值,默认10M

五、对比验证

spark3.2 开启AQE

http://szzb-bg-uat-etl-16:18080/history/application_1665940579703_5390/

spark3.2 关闭AQE

http://szzb-bg-uat-etl-16:18080/history/application_1665940579703_5812/

spark2.2 无AQE

http://szzb-bg-uat-etl-11:18080/history/application_1665940579703_9257/

5.1 执行耗时

使用资源: --driver-memory 6g --executor-memory 6g --executor-cores 6

耗时
spark3.2 开启AQE4.3 min
spark3.2 关闭AQE6.7 min
spark2.2 无AQE> 9.6min (OOM)
5.2 自动分区合并

在这里插入图片描述

5.3 自动数据倾斜处理

查看各stage执行时间

  • spark3.2 开启AQE 每个stage执行时间相差不大 (需要看每个stage的tasks )

  • spark2.2 无AQE 每个stage执行时间相差较大 (需要看每个stage的tasks )
    在这里插入图片描述

查看执行时间最长的stage数据分布

  • spark3.2 开启AQE Shuffle Read/Write 数据较均衡

  • spark2.2 无AQE Shuffle Read/Write 数据不均衡

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GB5NWCsF-1677203632031)(C:\Users\602946\AppData\Roaming\Typora\typora-user-images\image-20221019110500813.png)]

六、结论

spark3.2.2 开启AQE(默认开启),当Reduce Task 数据分布参差不齐时,能够自动合并过小的数据分区;且在 Reduce 阶段存在数据倾斜的情况下,能够拆分大分区;通过对比执行时间,AQE能极大的提升任务的执行效率。

### Spark AQE 工作机制及其优化场景 #### 工作机制 Spark 自适应查询执行(Adaptive Query Execution, AQE)是一种动态优化技术,用于改进 Spark SQL 查询性能。AQE 的核心在于能够在运行时重新规划物理执行计划,而不是依赖静态编译期决策。其工作机制主要包括以下几个方面: 1. **Join 策略调整** 在 Shuffle Map 阶段完成后,AQE 可以基于实际数据分布情况决定 Join 类型。例如,在广播连接中,如果某张表的数据量小于 `spark.sql.autoBroadcastJoinThreshold` 设置的阈值,则会将其作为广播表参与 Broadcast Hash Join;反之则可能切换到 Sort Merge Join[^1]。 2. **自动分区合并** 当 Shuffle 后的小文件过多时,AQE 能够通过参数 `spark.sql.adaptive.coalescePartitions.enabled=true` 动态减少下游任务的数量,从而降低计算开销并提高资源利用率。最终保留的最小分区数量由 `spark.sql.adaptive.coalescePartitions.minPartitionNum` 控制[^4]。 3. **自动倾斜处理** 对于存在数据倾斜的情况,AQE 提供了一种解决方案——将大 key 数据拆分至多个分区进行独立处理,以此缓解单个节点的压力。此功能可通过启用 `spark.sql.adaptive.skewJoin.enabled=true` 来实现。 #### 优化场景 AQE 特别适合那些涉及复杂操作且难以提前预知最佳执行策略的工作负载。具体而言: - 如果查询包含多次 Shuffle 操作,AQE 将发挥重要作用,因为它可以根据每次 Shuffle 结果实时调整后续阶段的行为[^3]。 - 不适用于无 Shuffle 场景下的简单查询,因为这些情况下不存在可调优的空间。 --- ### Spark DPP 实现方式与应用场景 #### 实现方式 Dynamic Partition Pruning (DPP),即动态分区裁剪,旨在进一步提升过滤条件传播效率,尤其是在大规模分布式存储环境中的分区表上应用效果显著。其实现有赖于 Catalyst Optimizer 中新增的一个规则类 `org.apache.spark.sql.execution.dynamicpruning.PartitionPruning.scala` 完成逻辑推导过程[^5]。 当遇到子查询或者关联表达式能够提供额外筛选信息时,Catalyst Engine 会在解析树构建期间尝试捕获此类约束,并传递给目标扫描算子完成更精细范围限定动作。这种做法有效减少了不必要的 I/O 开支以及内存消耗。 #### 应用场景 DPP 主要针对以下几种典型业务需求展现优势: - 处理超大数据集上的多维分析报表生成任务; - 支持 OLAP 性质的应用程序频繁访问历史积累资料库; - 加速 ETL 流程里跨系统间同步增量变更记录的过程。 ```sql -- 示例:利用 DPP 进行高效查询 SELECT * FROM sales s WHERE EXISTS ( SELECT 1 FROM regions r WHERE s.region_id = r.id AND r.name LIKE &#39;%North%&#39; ); ``` 上述例子展示了如何借助嵌套结构让外部谓词渗透进入内部关系集合之中,进而达成精准定位目的的同时也体现了良好兼容性特性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值