Spark AQE 特性怎么能使用好?

前言

Spark 3.0 发布后使用spark aqe 功能有时候效果并不理想,比如你打开了aqe 开关打开,相关的配置项也加上,但是性能还没有提升。 这是由于对Spark aqe 了解的不够透彻,调优总是依葫芦画瓢。所以这里先介绍下他设计的初衷以及他的工作原理,最后再去探讨怎么样更好的使用spark aqe。

Spark 为什么需要AQE

介绍AQE 前我们先介绍下Spark 2.0 前的一些spark sql 成果。

RBO (Rule Based Optimization)基于规则优化

Spark 2.0之前只 支持启发式优化(RBO),根据既有规则和策略实现,如谓词下推,列剪裁,这些策略来源于数据库领域已有的应用经验。算是一种经验主义的优化,
经验主义的弊端就是不分青红皂白,胡子眉毛一把抓,对待相似的问题和场景使用同一套路。

CBO(cost based Optimization)基于成本优化

Spark 2.2 版本应对RBO 经验主义的局限推出了CBO。基于数据表的统计信息(如表大小,数据列分布)来选择优化策略。根据各种统计信息如:表行数,每列的基数,空值数
最大值,最小值和直方图等等。应为有统计数据做支持所以CBO 的选择往往会优于RBO选择的优化。
But:
CBO也面临三种窘境:窄,慢,静。
窄:适用面窄,只支持注册到hive metastore 的数据表,但在大量的应用场景中,数据还存在在分布式数据文件系统上的各类文件,parquet,orc,csv 等
慢:统计信息的收集效率比较低,对于注册到hive metastore 的数据表,开发者需要调用 analyze table compute statistics 去收集统计信息,各类信息的收集会消耗大量时间
静:静态优化,与RBO 一样。CBO结合各类统计信息制定的计划执行。一旦执行计划制定,CBO就结束了。也就是说如果运行时数据分布发生动态变化,CBO 先前制定的执行计划并不会跟着调整适配。

所以考虑到rbo 和cbo 的种种限制,spark3.0 推出了aqe(自适应查询执行):spark sql 的一种动态优化机制,在运行时,每当shuffle map(shuffle write)执行完毕后,aqe 会结合这个阶段的统计信息
基于既定的规则动态的调整修改尚未执行的逻辑计划和物理计划。来完成对原始查询语句的优化。
注意:aqe 是基于shuffle 的操作,如果sql 语句中没有引入shuffle .那aqe 是爱莫能助的

Spark AQE 工作原理

AQE 依赖的统计信息与 cbo 不同,不是关于某张表或某个列的,而是shuffle map 阶段输出的中间文件。每个map task 输出的data 与index 文件。每个data文件大小,空文件数据与占比
每个reduce task 对应分区大小,所以这些基于中间文件的统计值构成了aqe 进行优化的信息来源。且从运行时获取的统计信息,在条件允许的情况下,会优化决策分别作用到逻辑计划和物理计划。
aqe 的规则和策略分位4个,分位1个逻辑优化规则和3个物理优化策略。如下图:
在这里插入图片描述

Join 策略调整:如果某张表在过滤后,尺寸小于广播变量阈值,这张表参与的数据关联就会从Shuffle Sort Merge Join 降级(Demote)为执行效率更高的Broadcast Hash Join
自动分区合并:在shuffle 之后,reduce task 数据分布参差不齐,aqe 将自动合并小的数据分区
自动倾斜处理:结合配置项,aqe 自动拆分Reduce 阶段过大的数据分区,降低单个Reduce Task 的工作负载,下面详细分析下这3个特性的详细过程:

Join 策略调整

Join 策略调整涉及一个逻辑规则和一个物理策略,分别是DemoteBroadcastHashJoin和OptimizeLocalShuffleReader。
DemoteBroadcastHashJoin规则的作业是把Shuffle Joins 降级为BroadCast join。但这个降级操作只适用于shuffle sort merge join 这种关联机制,其他机制如shuffle hash join、shuffle nested Loop join 都不支持。对于参与join 的两张表来说,在他们分别完成shuffle map 阶段之后,DemoteBroadcastHashjoin 会判断中间文件是否满足如下条件:
中间文件尺寸总和小于广播阈值
spark.sql.autoBroadcastJoinThreshold
空文件占比小于配置项
spark.sql.adaptive.nonEmptyPartitionRatioForBroadcastJoin.
只要任意一张表满足这两个条件,shuffle sort merge join 就会降级为broadcast hash join 。
那另一个规则OptimizeLocalShuffleReader 的作用是什么。我们知道,aqe 依赖shuffle map 阶段生成的中间文件。按常规的shuffle 计算流程,reduce 阶段的计算需要跨节点访问中间文件拉取分区数据分片。如果遵循常规步骤,即使AQE已经进行了降级策略,但是表的中间文件还是需要通过网络进行分发的。在这样的背景下OptimizeLocalShuffleReader 物理策略就非常重要了。可以省去shuffle 常规步骤中的网络分发,reduce task 可以读取本地节点local 的中间文件,完成与广播小表的关联操作。

自动分区合并

在reduce 阶段,当reduce task 从全网把数据分片拉回,aqe 按照分区编号的顺序,依次把小于目标尺寸的分区合并在一起。目标尺寸由下面两个参数决定:
分区合并后的推荐尺寸:spark.sql.adaptive.advisoryPartitionSizeInBytes
分区合并后不能低于值:spark.sql.adaptive.coalescePartition.minPartitionNum

自动倾斜处理

与自动合并分区相反,自动倾斜处理的操作是拆分。在reduce 阶段,当reduce task 所需处理的分区尺寸大于一定阈值时,利于optimizeSkewedJoin 策略,aqe 会把大分区才分成多个小分区。倾斜分区和拆分粒度由下面配置项决定:
判断倾斜的膨胀系数:
spark.sql.adaptive.skewjoin.skewedPartitionFactor
判定倾斜的最低阈值:
spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes
以字节为单位定义拆分粒度:
spark.sql.adaptive.advisoryPartitionSizeInBytes
需要注意,自动倾斜处理的拆分操作是在reduce阶段执行,在同一个executor内部,本该由一个Task 去处理的大分区,被AQE拆分成多个小分区并由task 去处理。这样task 之间的计算负载可以平衡,但是这并不能解决不同Executor 之间的负载均衡问题。
另外在关联场景中,对于参与join 的两张表,我们暂且把它们记做数据表1和数据表2.如果1中有倾斜的分区,2 中没有。那么在关联中,除了要拆分表1 的倾斜分区,还要对表2的对应的数据分区做复制来保证关联关系不会被破坏。那如果表1和表2都有倾斜呢。这个时候1,2也要各自的复制拆分出来的分区。比如表1拆分M,表2 拆分N。那么每张表最终都需要保持M×N份分区数据才能保证关联逻辑的一致性。当M和N逐渐变大时,AQE处理数据倾斜所需要的计算开销将面临失控的风险。
总的来说,如果应用场景中的数据倾斜比较简单,比如虽然有倾斜但数据分布相对均匀,或者关联计算中只有一边倾斜,那么我们完全可以依赖AQE的自动倾斜处理机制。但是当我们的场景中的数据倾斜变得复杂,比如数据中不同key 的分布悬殊,或者参与关联的两表都存在大量倾斜。那么我们就需要衡量AQE 的自动化机制与手工处理倾斜之间的利害得失。

总结

AQE 是 Spark SQL 的一种动态优化机制,它的诞生解决了 RBO、CBO,这些启发式、静态优化机制的局限性。想要用好 AQE,我们就要掌握它的特点,以及它支持的三种优化特性的工作原理和使用方法。
如果用一句话来概括 AQE 的定义,就是每当 Shuffle Map 阶段执行完毕,它都会结合这个阶段的统计信息,根据既定的规则和策略动态地调整、修正尚未执行的逻辑计划和物理计划,从而完成对原始查询语句的运行时优化。也因此,只有当你的查询语句会引入 Shuffle 操作的时候,Spark SQL 才会触发 AQE。

     AQE 支持的三种优化特性分别是 Join 策略调整、自动分区合并和自动倾斜处理。

关于 Join 策略调整:

我们首先要知道 DemoteBroadcastHashJoin 规则仅仅适用于 Shuffle Sort Merge Join 这种关联机制,对于其他 Shuffle Joins 类型,AQE 暂不支持把它们转化为 Broadcast Joins。其次,为了确保 AQE 的 Join 策略调整正常运行,我们要确保 spark.sql.adaptive.localShuffleReader.enabled 配置项始终为开启状态。

关于自动分区合并:

我们要知道,在 Shuffle Map 阶段完成之后,结合分区推荐尺寸与分区数量限制,AQE 会自动帮我们完成分区合并的计算过程。

关于 AQE 的自动倾斜处理:

我们要知道,它只能以 Task 为粒度缓解数据倾斜,并不能解决不同 Executors 之间的负载均衡问题。针对场景较为简单的倾斜问题,比如关联计算中只涉及单边倾斜,我们完全可以依赖 AQE 的自动倾斜处理机制。但是,当数据倾斜问题变得复杂的时候,我们需要衡量 AQE 的自动化机制与手工处理倾斜之间的利害得失。

  • 27
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值