Spark性能调优之合理分配系统资源以及并行度的调节

在Spark系统中,调优是非常重要。首先,调优的第一步也是首先要考虑的就是系统的资源,只有在合理、有效的分配完了系统的资源,才会去考虑其他调优点从而提升系统的性能与速度。虽然对于系统的资源的分配,看上去没那么难,但是也不能小视,一个集群或系统的资源有效,只有在知道其Spark资源分配的原理之后才能合理分配资源,一定程度上对系统的性能带来提升。

本篇文章主要从下面几个方面展开对系统资源的分配展开讨论:

  1. 需要分配哪些资源?
  2. 在哪里需要分配这些资源?
  3. 为什么分配了这些资源之后性能会带来提升?

一般情况下,我们了解一件事情都会从时间,地点,人物等等方面来着手,优化也不例外,我们必须知道如何优化,不仅如此,还要知道其原理,为何这样优化会给系统带来提升。

需要分配哪些资源?

Spark是一个内存计算框架,那么,内存的大小当然不例外,所以,driver memory、executor memory需要考虑,cpu的数量也需要考虑,具体是每一个executor所分配的cpu core的数量,还有就是executor的数量,这些都是需要考虑的。

在哪里分配这些资源?

一般的我们,会使用spark-submit方式来提交脚本执行spark任务,比如下面的脚本:

/usr/local/spark/bin/spark-submit \
--class cn.spark.sparktest.core.WordCountCluster \
--num-executors 3 \  配置executor的数量
--driver-memory 100m \  配置driver的内存(影响不大)
--executor-memory 100m \  配置每个executor的内存大小
--executor-cores 3 \  配置每个executor的cpu core数量
/usr/local/SparkTest-0.0.1-SNAPSHOT-jar-with-dependencies.jar \

因此,我们可以根据需要来尽可能大的分配集群的资源。

比如,每台机器4个cpu core,8G内存大小,10台机器,我们设计20个executor(一般可以分配几十个到上百个,根据spark任务的大小)。那么,每个executor可以分配4G内存大小,每一个executor分配2个cpu core。这样就可以尽可能大合理的分配集群资源。当然,上面只是举一个简单的例子,具体看系统的资源。

为什么这样分配资源会给系统性能带来优化?

在一个Spark集群中,我们会启动多个executor,然后各自分配任务。如下图所示:
这里写图片描述

在了解了Spark的内核架构之后(不懂的可以看之前的这篇文章Spark内核架构流程深度剖析)我们都知道DAGScheduler, TaskScheduler会将我们的算子切分为多个task,提交到Application的executor中执行。

增加每个executor的cpu core,也是增加了执行的并行能力。原本20个executor,每个才2个cpu core。能够并行执行的task数量,就是40个task。现在每个executor的cpu core,增加到了5个。能够并行执行的task数量,就是100个task。执行的速度,提升了2.5倍。

增加每个executor的内存量。增加了内存量以后,对性能的提升,有一下三点:

  1. 如果需要对RDD进行cache,那么更多的内存,就可以缓存更多的数据,将更少的数据写入磁盘,甚至不写入磁盘。减少了磁盘IO。

  2. 对于shuffle操作,reduce端,会需要内存来存放拉取的数据并进行聚合。如果内存不够,也会写入磁盘。如果给executor分配更多内存以后,就有更少的数据,需要写入磁盘,甚至不需要写入磁盘。减少了磁盘IO,提升了性能。

  3. 对于task的执行,可能会创建很多对象。如果内存比较小,可能会频繁导致JVM堆内存满了,然后频繁GC,垃圾回收,minor GC和full GC。(速度很慢)。内存加大以后,带来更少的GC,垃圾回收,避免了速度变慢,因此在速度变快了。

如果executor数量比较少,那么,能够并行执行的task数量就比较少,就意味着,我们的Application的并行执行的能力就很弱。

比如有3个executor,每个executor有2个cpu core,那么同时能够并行执行的task,就是6个。6个执行完以后,再换下一批6个task。

增加了executor数量以后,那么,就意味着,能够并行执行的task数量,也就变多了。比如原先是6个,现在可能可以并行执行10个,甚至20个,100个。那么并行能力就比之前提升了数倍,数十倍。相应的,性能(执行的速度),也能提升数倍~数十倍。

2018-08-11补充
在讲述完系统资源如何合理分配之后,我们来探究一下如何调节Spark作业的并行度

首先,我们要知道什么是Spark作业的并行度:所谓并行度,就是指Spark作业每个stage的task数量,也代表了各个stage的并行度。

那么,如何调节并行度呢?假设Spark集群有30个executor,每个executor分配5个cpu core,此时,总共有150个cpu core,如果我们设置100个task,那么就会有空闲的cpu,致使资源的浪费,因此在理想状况下我们应该设置150个task,让每一个cpu都不空闲下来。

但是理想并非现实,我们可以想象这样一个场景,每个task的运行时间不可能全部相等,有的task运行时间很长,有的task运行时间很短,那么,运行时间短的task先运行完毕,按照上面设置task数量和cpu数量一样的话就会导致运行完时间短的task的cpu空闲下来,这样,也会影响Spark作业完成的进度。

所以,在一般情况下,我们会设置task的数量是cpu数量的2~3倍。这样设置的原因:可以让运行时间短的task在运行完毕之后分配给该cpu其他的task来运行,这样就可以更加合理的利用cpu资源,同时也可以减小Spark作业运行的时间。

如果一个Spark集群中有100个cpu core,那么我们可以在创建SparkConf的时候使用spark.default.parallelism 参数这样设置:

SparkConf conf = new SparkConf()
  .set("spark.default.parallelism", "250")

在理解了上述的原理之后,相信你会对于系统资源的分配以及并行度的设置会有更加深入的理解,对于自己的应用,也会熟练操作,资源的分配往往被开发者忽略,在优化时总是在其他很高端的地方想着优化,其实在分配好系统资源以及调节作业的并行度之后,再优化其他地方,往往会给你的应用带来更好的优化。以上就是我的个人理解,如有任何问题,欢迎留言讨论!!!


猜你喜欢

转载自blog.csdn.net/qq_37142346/article/details/81490314
今日推荐