![d6e9c4bd961956548df2a9bd1afd6449.gif](https://img-blog.csdnimg.cn/img_convert/d6e9c4bd961956548df2a9bd1afd6449.gif)
![0bdffabb9366e415d0c5a99877741030.png](https://img-blog.csdnimg.cn/img_convert/0bdffabb9366e415d0c5a99877741030.png)
多年大数据运维/数仓开发经验,擅长数仓模型开发、平台运维;参与/主导金融/教育等客户的大数据数仓建设;负责多家客户的大数据业务场景落地。
![d6e9c4bd961956548df2a9bd1afd6449.gif](https://img-blog.csdnimg.cn/img_convert/d6e9c4bd961956548df2a9bd1afd6449.gif)
01
Spark资源参数优化
主要针对Spark运行过程中各个使用资源的地方,通过调节资源相关参数,来优化资源使用的效率,从而提升Spark作业的执行性能。例如:num-executors、executor-memory、executor-cores等。
02
Shuffle相关参数调优
主要针对spark运行过程中的shuffle,通过调节参数,提高shuffle的执行效率,从而提升spark作业的执行性能。例如:spark.shuffle.memoryFraction,
spark.sql.shuffle.partitions等。
案例1
某天晨间巡检,工程师发现有任务报错,任务sql大约有400行,较为复杂,join聚合函数操作较多。手动重试任务后仍然报错。
查看任务报错日志
![dca958976a30453b3e682bebcfe5212d.png](https://img-blog.csdnimg.cn/img_convert/dca958976a30453b3e682bebcfe5212d.png)
分析关键信息
Exception in thread "broadcast-exchange-0" java.lang.OutOfMemoryError: Not enough memory to build and broadcast the table to all worker nodes. As a workaround, you can either disable broadcast by setting spark.sql.autoBroadcastJoinThreshold to -1 or increase the spark driver memory by setting spark.driver.memory to a higher value
得出结论
当前所有的工作节点均没有足够的内存去build并且广播表,建议处理方法:将广播置为无效或者增加spark的driver memory。
优化效果
经过对比测试验证,在同时调大excutor内存和driver内存后,任务可以成功运行。单独调大driver或excutor内存,任务运行依然失败。
Q
思考:什么情况下应将广播设置为无效?
答:根据官网文档对该参数的描述可知:其默认值为10M,意味着执行join时,这张表字节大小在10M内可以自动广播到所有工作节点。将表广播到其他工作节点,会减少shuffle的过程,提升效率。如果在内存足够并且数据量过多的情况下,可以将适当提高该参数值作为一种优化手段。如果在表都很大的情况下,建议将自动广播参数置为无效。将参数值设置为-1时会禁用自动广播。
![7b695aa6f19c525f8bd6b446c003f134.png](https://img-blog.csdnimg.cn/img_convert/7b695aa6f19c525f8bd6b446c003f134.png)
案例2
某日工程师在编写客户运维日报时,发现某个任务已经运行了40多个小时,自动重试了3次,且处于阻塞状态。
查看异常任务SQL
发现任务中由10多个SQL语句构成,一个语句大概有200+行,union all、join、sum操作较多。
查看任务报错日志
![e3600c06aae261eb62a44d369ff610f4.png](https://img-blog.csdnimg.cn/img_convert/e3600c06aae261eb62a44d369ff610f4.png)
分析关键信息
org.apache.spark.shuffle.MetadataFetchFailedException: Missing an output location for shuffle 433
得出结论
一般任务有大量shuffle操作的时候,我们可以从shuffle数据量及shuffle分区数的角度对任务进行优化调整。
优化效果
只采取调大executor内存的方式进行优化,任务可以运行成功,但任务执行耗时仍然需20+分钟,执行效率与优化前相比无明显变化。原因在于任务执行中产生了较多的task,此时可以通过调整分区参数进行深入优化。分区参数spark.sql.shuffle.partitions是Spark SQL专用的设置,将该参数的值由200(默认值)调小为50,任务运行成功,执行耗时减少50%,约10分钟;继续将该参数调小为10,任务运行成功,执行耗时减少70%,约6分钟,优化完成。
Q
思考:spark.default.parallelism参数与
spark.sql.shuffle.partitions参数有什么区别?
答:虽然这两个参数较为相似,但default.parallelism只在处理RDD时才会起作用,对Spark SQL无效。其值设置为【num- executors * executor-cores】的2~3倍较为合理。可以参考官网的定义说明:
![ba392a360a6e440acfbe412947d326fd.png](https://img-blog.csdnimg.cn/img_convert/ba392a360a6e440acfbe412947d326fd.png)
延伸拓展 ·
1.shuffle分为shuffle write和shuffle read两部分。
2.shuffle write的分区数由上一阶段的RDD分区数控制,shuffle read的分区数则是由Spark提供的一些参数控制。
3.shuffle write可以简单理解为类似于saveAsLocalDiskFile的操作,将计算的中间结果按某种规则临时放到各个executor所在的本地磁盘上。
4.shuffle read时数据的分区数则是由spark提供的一些参数控制。如果这个参数值设置的很小,同时shuffle read的量很大,那么将会导致一个task需要处理的数据非常大,容易引发JVM crash。如果这个参数值设置的很大,可能会导致task的数量过多,任务执行速度过慢。
job和stage以及task的关系如下图所示,job的划分是action操作造成的,Stage是job通过依赖关系划分出来的,一个Stage对应一个TaskSet,一个Task对应一个rdd分区。同时大量使用shuffle操作也会使task数量变多。
写在最后
![7b6ab35b9c7dc735608a9e57fa3c17ab.gif](https://img-blog.csdnimg.cn/img_convert/7b6ab35b9c7dc735608a9e57fa3c17ab.gif)
本次优化主要是结合实际优化案例,对底层引擎spark的参数进行调优。如何通过优化提升任务执行效率?如何利用监控分析将被动运维转为主动运维?请关注后续Hive性能优化及监控方面的实践连载。
![34a2c6fa6c3e1e1ccd7daa5bfc57d122.png](https://img-blog.csdnimg.cn/img_convert/34a2c6fa6c3e1e1ccd7daa5bfc57d122.png)