Spark优化
第一章 Explain查看执行计划
- 准备测试用表和数据
- 基本语法
- 执行计划处理流程
执行计划处理流程
核心处理主要有以下5个步骤:
CPU优化
1.CPU低效原因
概念理解
- 并行度(task)
spark.default.parallelism
设置RDD的默认并行度,没有设置时,由join、reduceByKey和parallelize等转换决定。
2.spark.sql.shuffle.partitions
适用SparkSQL时,shuffle Reduce阶段默认的并行度,默认200,此参数只能控制Spark sql,DataFrame,DataSet分区个数,不能控制RDD分区个数。 - 并发度:同时执行的task数量
低效原因
1.并行度较低,数据分片较大容易导致CPU线程挂起
2.并行度过高,数据过于分散会让调度开销更多
Executor接收到TaskDescription之后,首先需要对TaskDescription反序列化才能读取任务信息,然后将任务代码再反序列化得到可执行代码,最后再结合其他任务信息创建TaskRunner。当数据过于分散,分布式任务数量会大幅增加,但每个任务需要处理的数据量却少之又少,就CPU消耗来说,相比花在数据处理上的比例,任务调度上的开销几乎与之分庭抗礼。显然,在这种情况下,CPU的有效利用也是极低的。
合理利用CPU资源
每个并行度的数据量(总数据量/并行度)在(Executor内存/core数/2,Executor内存/core数)区间。
提交执行:
spark-submit -- master yarn -- deploy-mode client -- driver-memory 1g -- num-executors 3 -- executor-cores 4 -- executor-memory 6g -- class com.atguigu.sparktuning.partition.PartitionDemo spark-tuuning-1.0-SNAPSHOT-jar-with-dependencies.jar
去向
yarn申请的executor vcore资源个数为12个(num-executor*executor-cores),如果不修改spark sql分区个数,那么就会像上图所展示在cpu空转的情况。这个时候需要合理控制shuffle分区个数。如果想要让任务运行的最快当然是一个task对应一个vcore,但是一般不会这样设置,为了合理利用资源,一般会将并行度(task数)设置成并发度(vcore数)的2倍到3倍。
第三章 SparkSQL语法优化
SparkSQL在整个执行计划处理的过程中,使用了Catalyst优化器。
3.1 基于RBO的优化
在Spark3.0版本中,Catalyst总共有81条优化规则
1.谓词下推(Predicte Pushdown)
将过滤条件的谓词逻辑都尽可能提前执行,减少下游处理的数据量。对应PushDownPredicte优化规则,对于Parquet、ORC这类存储格式,结合文件脚注(Footer)中的统计信息,下推的谓词能够大幅度减少数据扫描量,降低磁盘I/O开销。
左外关联下推规则:左表left join 右表
左表 | 右表 | |
---|---|---|
join中条件(on) | 只下推右表 | 只下推右表 |
join后条件(where) | 两表都下推 | 两表都下推 |
注意:外关联时,过滤条件写在on与where,结果是不一样的! |
2.列裁剪(column pruning)
列裁剪就是扫描数据源时候,只读取那些与查询相关的字段。
3. 常量替换(constant folding)
假设我们在年龄上加的过滤条件是“age<12+18”,Catalyst会使用ConstantFolding规则,自动帮我们把条件变成"age<30"。再比如,我们在select语句中,掺杂了一些常量表达式,Catalyst也会自动地用表达式的结果进行替换。
3.2基于CBO的优化
CBO优化主要在物理计划层面,原理是计算所有可能的物理计划的代价,并挑选出代价最小的物理执行计划。充分考虑了数据本身的特点(如大小、分布)以及操作算子的特点(中间结果集的分布及大小)及代价,从而更好的选择执行代价最小的物理执行计划。
而每个执行计划节点的代价,分分为两个部分:
1.该执行节点对数据集的影响,即该节点输出数据集的大小与分布;
2.该执行节点操作算子的代价
每个操作算子的代价相对固定,可用规则来描述,而执行节点输出数据集的大小与分布,分为两个部分:
1.出事数据集,也即为原始表,其数据集的大小与分布可直接通过统计得到;
2.中间节点输出数据集的大小与分布可由其输入数据集的信息与操作本身的特点推算。
3.4 SMB Join(大表join大表)
SMB JOIN是sort merge bucket操作,需要进行分桶,首先会进行排序,然后根据key值合并,把相同的数据放到同一个bucket中(按照key进行hash)。分桶的目的其实就是把大表化成小表,相同key的数据都在同一个桶之后,再进行join操作,那么在联合的时候就会大幅度的减少无关项的扫描。
使用条件:
(1)两表进行分桶,桶的个数必须相等;
(2)两边进行join时,join列=排序列=分桶列