8.spark自适应查询-AQE之自适应调整Shuffle分区数量

SparkSQL的自适应查询执行(AQE)通过动态调整Shuffle分区数量来优化性能。文章介绍了AQE的主要功能,包括如何自适应地合并小分区以减少资源浪费,以及默认配置和如何修改配置以适应不同场景。

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

概述

自适应查询执行(AQE)是 Spark SQL中的一种优化技术,它利用运行时统计信息来选择最高效的查询执行计划,自Apache Spark 3.2.0以来默认启用该计划。从Spark 3.0开始,AQE有三个主要功如下

  • 自适应查询AQE(Adaptive Query Execution)
    • 自适应调整Shuffle分区数量
      • 原理
      • 默认环境配置
      • 修改配置
    • 动态调整Join策略
    • 动态优化倾斜的 Join

主要功能

自适应调整Shuffle分区数量

spark.sql.adaptive.enabledspark.sql.adaptive.coalescePartitions.enabled配置均为true时,自适应调整Shuffle分区数量功能就启动了

属性名称默认值功能版本
spark.sql.adaptive.enabledtrue必备条件之一3.0.0
spark.sql.adaptive.coalescePartitions.enabledtrue必备条件之二3.0.0
spark.sql.adaptive.advisoryPartitionSizeInBytes64 MB自适应优化期间shuffle分区的建议大小(以字节为单位)。当Spark合并小的shuffle分区或拆分倾斜的shuffler分区时,它就会生效。3.0.0
spark.sql.adaptive.coalescePartitions.parallelismFirsttrue当为true时,Spark在合并连续的shuffle分区时会忽略Spark.sql.adaptive.advisoryPartitionSizeInBytes(默认64MB)指定的目标大小,并且只遵循Spark.sql.adaptive.salecePartitions.minPartitionSize(默认1MB)指定的最小分区大小,以最大限度地提高并行性。这是为了在启用自适应查询执行时避免性能回归建议将此配置设置为false,并遵守spark.sql.adaptive.advisoryPartitionSizeInBytes指定的目标大小。3.2.0

原理

Spark在处理海量数据的时候,其中的Shuffle过程是比较消耗资源的,也比较影响性能,因为它需要在网络中传输数据
shuffle 中的一个关键属性是:分区的数量。
分区的最佳数量取决于数据自身大小,但是数据大小可能在不同的阶段、不同的查询之间有很大的差异,这使得这个数字很难精准调优。
如果分区数量太多,每个分区的数据就很小,读取小的数据块会导致IO效率降低,并且也会产生过多的task, 这样会给Spark任务带来更多负担。
如果分区数量太少,那么每个分区处理的数据可能非常大,处理这些大分区的数据可能需要将数据溢写到磁盘(例如:排序或聚合操作),这样也会降低计算效率。

Spark初始会设置一个较大的Shuffle分区个数,这个数值默认是200,后续在运行时会根据动态统计到的数据信息,将小的分区合并,也就是慢慢减少分区数量。

测试时将以SELECT workorder,unitid,partid,partname,routeid,lineid from ods.xx where dt ='2023-06-24' group by workorder,unitid,partid ,partname ,routeid,lineid 语句进行测试,为了看出 Shuffle 的效果,group 字段多了一些

将初始的 Shuffle 分区数量设置为 5,所以在 Shuffle 过程中数据会产生5 个分区。如果没有开启自适应调整Shuffle分区数量这个策略,Spark会启动5个Recuce任务来完成最后的聚合。但是这里面有3个非常小的分区,为每个分区分别启动一个单独的任务会浪费资源,并且也无法提高执行效率。如下图:
在这里插入图片描述
开启自适应调整 Shuffle 分区数量之后,Spark 会将这3个数据量比较小的分区合并为 1 个分区,让1个reduce任务处理
在这里插入图片描述

默认环境配置

测试案例:

案例环境,使用的是 spark 3.2.4kyuubi 1.7.1 版本,使用一张 20 亿的表做优化测试的,也可以准备一个 json 文件,加载后转成 DataFrame

在这里插入图片描述

SELECT  workorder,unitid,partid,partname,routeid,lineid  from ods.xx where dt ='2023-06-24' group by workorder,unitid,partid ,partname ,routeid,lineid 

在这里插入图片描述
在这里插入图片描述

由上两个图,可以看出21任务,每个任务只是 3~4 M 这样,原因是因

spark.sql.adaptive.coalescePartitions.parallelismFirst = true

修改配置

spark.sql.adaptive.coalescePartitions.parallelismFirst=false

在这里插入图片描述
在这里插入图片描述
可以看出,两三千万的数据,shuffle 处理上还是有倾斜的,但海量数据下,基本上是接近64m的。

结束

至此,自适应调整Shuffle分区数量,就结束了。

### 设置 Spark 默认并行度为 400 的方法 在 Spark 中,可以通过多种方式设置默认的并行度(`default parallelism`)。以下是几种常见的配置方法: #### 方法一:通过 `spark.default.parallelism` 参数 可以在 Spark 配置文件或启动应用程序时指定该参数来设置全局默认并行度。具体操作如下: - 如果使用的是 Spark Shell 或其他交互环境,在启动命令中加入以下选项即可完成配置: ```bash --conf spark.default.parallelism=400 ``` - 对于集群模式下的作业提交,也可以通过 `--conf` 参数传递给 `spark-submit` 工具[^1]。 #### 方法二:修改 Spark 配置文件 对于长期运行的任务或者固定部署场景,可以编辑 Spark 的配置文件 `spark-defaults.conf` 并添加以下内容: ```properties spark.default.parallelism 400 ``` 保存更改后重启 Spark 应用程序以使新配置生效[^3]。 #### 方法三:动态调整 Shuffle 分区数量 除了上述静态设定外,还可以针对特定任务灵活控制其分区数目。例如当执行 SQL 查询语句前可临时改变 shuffle partitions 数量至目标值 (此处设为400),即执行下面这条指令之前的所有后续shuffle操作都将采用新的定义好的partition count: ```sql SET spark.sql.shuffle.partitions=400; ``` ### 处理与化性能问题 即使设置了较高的初始并行级别也可能遇到某些特殊情况比如数据分布不均等问题影响整体效率表现。此时就需要借助更高级别的特性来进行进一步微: #### 开启自适应查询执行(AQE) 启用 AQE 功能可以帮助系统自动识别潜在的数据倾斜状况并对之采取相应措施而无需人工干预过多细节部分。主要涉及以下几个关键参数节: - **开启AQE**: 将 `spark.sql.adaptive.enabled=true` 添加到您的应用配置当中去激活整个机制。 - **处理倾斜连接** : 启用 skew join 自动检测和缓解策略,确保相关联表间存在显著差异大小关系时候能够有效应对可能出现的大规模重复计算现象. * 设定阈值判断标准:`spark.sql.adaptive.skewJoin.skewedPartitionFactor`=X(推荐保持原厂预设5不变除非特殊需求); * 明确触发条件界限: `spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes`=Y字节单位表示达到多少容量以上才被认定属于严重失衡范畴值得特别对待. 这些做法共同作用之下往往能带来较为明显的提速效果同时减少资源浪费情况发生概率[^4]. ### 示例代码片段展示如何初始化带有定制化属性的对象实例 ```scala import org.apache.spark.SparkConf import org.apache.spark.sql.SparkSession val conf = new SparkConf() .setAppName("CustomParallelismApp") .setMaster("local[*]") .set("spark.default.parallelism", "400") val spark = SparkSession.builder.config(conf).getOrCreate() // 执行业务逻辑... println(s"Current default parallelism is set to ${spark.conf.get("spark.default.parallelism")}") ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流月up

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值