Spark性能优化-------资源调优

350 阅读5分钟

为作业配置合适的资源,Spark的资源参数,基本都可以在spark-submit命令中作为参数设置。

\

Spark作业基本运行原理\

Spark性能优化-------资源调优 X

\

使用spark-submit提交一个Spark作业后,这个作业就会启动一个对应的Driver进程,根据使用的部署模式(deploy-mode)不同,Driver进程可能在本地启动,也可能在集群中某个工作节点上启动。Driver进程本身会根据设置的参数,占有一定数量的内存和CPU core。而Driver进程要做得第一件事,就是向集群管理器申请运行Spark作业需要使用的资源,这里的资源指的就是Executor进程,集群管理器会根据为Spark作业设置的资源参数,在各工作节点上,启动一定数量的Executor进程,每个Executor进程都占有一定数量的内存和CPU core。

\

在申请到作业执行所需的资源之后,Driver进程会开始调度和执行我们编写的代码了。Driver进程会将我们编写的Spark作业代码分拆为多个stage,每个stage执行一部分代码片段,并为每个stage创建一批task,然后将这些task分配到各个Executor进程中执行。task是最小的计算单元,负责执行一模一样的计算逻辑,只是每个task处理的数据不同而已。一个stage的所有task都执行完毕之后,会在各个节点本地的磁盘文件中写入计算中间结果,然后Driver就会调度运行下一个stage。下一个stage的task的输入数据就是上一个stage输出的结果。

\

Executor的内存主要分为三块:第一块是让task执行代码时使用,默认是占Executor总内存的20%;第二块是让task通过shuffle过程拉取上一个stage的task的输出后,进行聚合等操作时使用,默认也是20%;第三块是让RDD持久化时使用,默认是占Executor总内存的60%。

\

task的执行速度是跟每个Executor进程的CPU core数量有直接关系的。一个CPU core同一时间只能执行一个线程,而每个 Executor进程上分配到的多个task,都是以每个task一条线程的方式,多线程并发执行的。如果CPU core数量比较充足,而且分配到的task数量比较合理,那么通常来说,可以比较快速和高效地执行这些task线程。

\

所谓的Spark资源参数调优,主要就是对Spark运行过程中各个使用资源的地方,通过调节各种参数,来优化资源使用的效率,从而提升Spark作业的执行性能。

\

num-executors
参数说明:设置Spark作业总共要用多少个Executor进程来执行。\

调优建议:每个Spark作业的运行一般设置50-100个左右的Executor进程比较合适。

\

executor-memory
参数说明:设置每个Executor进程的内存。\

调优建议:每个Executor进程的内存设置4G-8G较为合适,具体的设置还是要根据不同部分的资源队列来定。num-executor乘以executor-memory,就代表了Spark作业申请到的总内存量,这个量不要超过队列的最大内存量的,也不要占用过多,以免影响其他的Spark作业运行。

\

executor-cores
参数说明:设置每个Executor进程的CPU core数量,这个参数决定了每个Executor进程并行执行task线程的能力。因为每个CPU core同一时间只能执行一个task线程,因此每个Executor进程的CPU core数量越多,越能并行计算。\

调优建议:Executor的CPU core数量设置为2-4个比较合适。

\

driver-memory
参数说明:设置Driver进程的内存。\

调优建议:Driver的内存通常来说不设置,或者设置1G左右就够了。但是如果要使用collect算子将RDD的数据全部拉取到Driver上进行处理,必须要确保Driver的内存足够大,否则就会出现OOM内存溢出的问题。

\

spark.default.parallelism
参数说明:设置每个stage的默认task数量。\

调优建议:Spark作业的默认task数量为500-1000个较为合适。不设置会导致Spark根据底层HDFS的block数量来设置task的数量,默认一个HDFS block对应一个task,通常来说,Spark默认设置的数量是偏少的,如果task数量偏少的话,就会导致前面设置好的Executor的参数都前功尽弃。设置该参数为num-executors*executor-cores的2-3倍较为合适。

\

spark.storage.memoryFraction
参数说明:设置RDD持久化数据在Executor内存中能占的比例,默认是0.6。\

调优建议:Spark作业中,如果有较多的RDD持久化操作,调高这个参数。如果Spark作业中shuffle类操作比较多,而持久化操作比较少,这个参数降低一些比较合适。如果发现作业频繁的gc导致运行缓慢(spark web UI可查看作业的gc耗时),意味着task执行用户代码的内粗不够用,那么建议调低这个参数的值。

\

spark.shuffle.memoryFraction
参数说明:设置shuffle过程中一个task拉取到上个stage的输出后,进行聚合操作时能够使用的Executor内存的比例,默认是0.2。\

调优建议:如果Spark作业的RDD持久化操作比较少,shuffle操作较多时,建议调低持久化操作的内存占比,提高shuffle操作的内存占比比例,避免shuffle过程中数据过多时内存不够用,必须溢写到磁盘上,减低性能。如果发现作业频繁的gc导致运行缓慢,意味着task执行用户代码的内存不够用,那么建议调低这个参数的值。

\