Spark Adaptive Execution

本文讨论了Apache Spark SQL在大规模数据集上遇到的挑战,如shuffle partition数、执行计划选择和数据倾斜问题,并介绍了自适应执行引擎的背景、架构以及如何应对这些挑战。自适应执行可以根据运行时信息自动调整shuffle partition数、动态优化执行计划和处理数据倾斜,从而提高性能。在100TB TPC-DS基准测试中,自适应执行在92%的查询中提升了性能,最高提升达3.8倍。
摘要由CSDN通过智能技术生成

最近遇到了很多spark性能优化的问题,刚好找到了一篇比较全面的总结,但没有给出具体实现方法。

所以这边打算罗列一下计划优化的点,慢慢抽时间研究、优化,最后打算应用到公司业务中,并争取贡献到spark社区。

---------------------------------------------------------------------------------------------------------------------------------------------------------------

Spark SQL是Apache Spark最广泛使用的一个组件,它提供了非常友好的接口来分布式处理结构化数据,在很多应用领域都有成功的生产实践,但是在超大规模集群和数据集上,Spark SQL仍然遇到不少易用性和可扩展性的挑战。为了应对这些挑战,英特尔大数据技术团队和百度大数据基础架构部工程师在Spark 社区版本的基础上,改进并实现了自适应执行引擎。本文首先讨论Spark SQL在大规模数据集上遇到的挑战,然后介绍自适应执行的背景和基本架构,以及自适应执行如何应对Spark SQL这些问题,最后我们将比较自适应执行和现有的社区版本Spark SQL在100 TB 规模TPC-DS基准测试碰到的挑战和性能差异,以及自适应执行在Baidu Big SQL平台的使用情况。

 

挑战1:关于shuffle partition数

 

在Spark SQL中, shufflepartition数可以通过参数spark.sql.shuffle.partition来设置,默认值是200。这个参数决定了SQL作业每个reduce阶段任务数量,对整个查询性能有很大影响。假设一个查询运行前申请了E个Executor,每个Executor包含C个core(并发执行线程数),那么该作业在运行时可以并行执行的任务数就等于E x C个,或者说该作业的并发数是E x C。假设shuffle partition个数为P,除了map stage的任务数和原始数据的文件数量以及大小相关,后续的每个reduce stage的任务数都是P。由于Spark作业调度是抢占式的,E x C个并发任务执行单元会抢占执行P个任务,“能者多劳”,直至所有任务完成,则进入到下一个Stage。但这个过程中,如果有任务因为处理数据量过大(例如:数据倾斜导致大量数据被划分到同一个reducer partition)或者其它原因造成该任务执行时间过长,一方面会导致整个stage执行时间变长,另一方面E x C个并发执行单元大部分可能都处于空闲等待状态,集群资源整体利用率急剧下降。

 

那么spark.sql.shuffle.partition参数究竟是多少比较合适?如果设置过小,分配给每一个reduce任务处理的数据量就越多,在内存大小有限的情况下,不得不溢写(spill)到计算节点本地磁盘上。Spill会导致额外的磁盘读写,影响整个SQL查询的性能,更差的情况还可能导致严重的GC问题甚至是OOM。相反,如果shuffle partition设置过大。第一,每一个reduce任务处理的数据量很小并且很快结束,进而导致Spark任务调度负担变大。第二,每一个mapper任务必须把自己的shuffle输出数据分成P个hash bucket,即确定数据属于哪一个reduce partition,当shuffle partition数量太多时,hash bucket里数据量会很小,在作业并发数很大时,reduce任务shuffle拉取数据会造成一定程度的随机小数据读操作,当使用机械硬盘作为shuffle数据临时存取的时候性能下降会更加明显。最后,当最后一个stage保存数据时会写出P个文件,也可能会造成HDFS文件系统中大量的小文件。

 

从上,shuffle partition的设置既不能太小也不能太大。为了达到最佳的性能,往往需要经多次试验才能确定某个SQL查询最佳的shuffle partition值。然而在生产环境中,往往SQL以定时作业的方式处理不同时间段的数据,数据量大小可能变化很大,我们也无法为每一个SQL查询去做耗时的人工调优,这也意味这些SQL作业很难以最佳的性能方式运行。

 

Shuffle partition的另外一个问题是,同一个shuffle partition数设置将应用到所有的stage。Spark在执行一个SQL作业时,会划分成多个stage。通常情况下,每个stage的数据分布和大小可能都不太一样,全局的shuffle partition设置最多只能对某个或者某些stage最优,没有办法做到全局所有的stage设置最优。

 

这一系列关于shufflepartition的性能和易用性挑战,促使我们思考新的方法:我们能否根据运行时获取的shuffle数据量信息,例如数据块大小,记录行数等等,自动为每一个stage设置合适的shuffle partition值?

 

挑战2:Spark SQL最佳执行计划

 

Spark SQL在执行SQL之前,会将SQL或者Dataset程序解析成逻辑计划,然后经历一系列的优化,最后确定一个可执行的物理计划。最终选择的物理计划的不同对性能有很大的影响。如何选择最佳的执行计划,这便是Spark SQL的Catalyst优化器的核心工作。Catalyst早期主要是基于规则的优化器(RBO),在Spark 2.2中又加入了基于代价的优化(CBO)。目前执行计划的确定是在计划阶段,一旦确认以后便不再改变。然而在运行期间,当我们获取到更多运行时信息时,我们将有可能得到一个更佳的执行计划。

 

以join操作为例,在Spark中最常见的策略是BroadcastHashJoin和SortMergeJoin。BroadcastHashJoin属于map side join,其原理是当其中一张表存储空间大小小于broadcast阈值时,Spark选择将这张小表广播到每一个Executor上,然后在map阶段,每一个mapper读取大表的一个分片,并且和整张小表进行join,整个过程中避免了把大表的数据在集群中进行shuffle。而SortMergeJoin在map阶段2张数据表都按相同的分区方式进行shuffle写,reduce阶段每个reducer将两张表属于对应partition的数据拉取到同一个任务中做join。RBO根据数据的大小,尽可能把join操作优化成Br

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值