目录

  • 1、静态资源调度 
  • 2、动态资源调度
  • 3、配置 hadoop 中 yarn 相关文件
  • 4、启动 spark 作业查看是否动态资源调度 

1、静态资源调度

      当一个spark application运行在集群中时,会获取一批独立的executor进程专门为自己服务,比如运行task和存储数据。如果多个用户同时在使用一个集群,并且同时提交多个作业,那么根据cluster manager的不同,有几种不同的方式来管理作业间的资源分配。最简单的一种方式,是所有cluster manager都提供的,也就是静态资源分配。在这种方式下,每个作业都会被给予一个它能使用的最大资源量的限额,并且可以在运行期间持有这些资源。这是spark standalone集群和YARN集群使用的默认方式。

    (1) Standalone集群: 默认情况下,提交到standalone集群上的多个作业,会通过FIFO的方式来运行,每个作业都会尝试获取所有的资源。可以限制每个作业能够使用的cpu core的最大数量(spark.cores.max),或者设置每个作业的默认cpu core使用量(spark.deploy.defaultCores)。最后,除了控制cpu core之外,每个作业的spark.executor.memory也用来控制它的最大内存
的使用。

    (2)YARN: --num-executors属性用来配置作业可以在集群中分配到多少个executor,--executor-memory和--executor-cores可以控制每个executor能够使用的资源。

2、动态资源调度

       spark 1.2开始,引入了一种根据作业负载动态分配集群资源给你的多个作业的功能。这意味着你的作业在申请到了资源之后,可以在使用完之后将资源还给cluster manager,而且可以在之后有需要的时候再次申请这些资源。这个功能对于多个作业在集群中共享资源是非常有用的。如果部分资源被分配给了一个作业,然后出现了空闲,那么可以还给cluster manager的资源池中,并且被其他作业使用。在spark中,动态资源分配在executor粒度上被实现,可以通过spark.dynamicAllocation.enabled来启用。

(1)资源分配策略

      当executor不再被使用的时候,spark就应该释放这些executor,并且在需要的时候再次获取这些executor。因为没有一个绝对的方法去预测一个未来可能会运行一个task的executor应该被移除掉,或者一个新的executor应该别加入,我们需要一系列的探索式算法来决定什么应该移除和申请executor。

(2)申请策略

       一个启用了动态资源分配的spark作业会在它有pending住的task等待被调度时,申请额外的executor。这个条件必要地暗示了,已经存在的executor是不足以同时运行所有的task的,这些task已经提交了,但是没有完成。driver会轮询式地申请executor。当在一定时间内(spark.dynamicAllocation.schedulerBacklogTimeout)有pending的task时,就会触发真正的executor申请,然后每隔一定时间后(spark.dynamicAllocation.sustainedSchedulerBacklogTimeout),如果又有pending的task了,则再次触发申请操作。此外,每一轮申请到的executor数量都会比上一轮要增加。举例来说,一个作业需要增加一个executor在第一轮申请时,那么在后续的一轮中会申请2个、4个、8个executor。

      每轮增加executor数量的原因主要有两方面。第一,一个作业应该在开始谨慎地申请以防它只需要一点点executor就足够了。第二,作业应该会随着时间的推移逐渐增加它的资源使用量,以防突然大量executor被增加进来。

(3)移除策略

移除一个executor的策略比较简单。一个spark作业会在它的executor出现了空闲超过一定时间后(spark.dynamicAllocation.executorIdleTimeout),被移除掉。要注意,在大多数环境下,这个条件都是跟申请条件互斥的,因为如果有task被pending住的话,executor是不该是空闲的。

executor如何优雅地被释放掉?

       在使用动态分配之前,executor无论是发生了故障失败,还是关联的application退出了,都还是存在的。在所有场景中executor关联的所有状态都不再被需要,并且可以被安全地抛弃。使用动态分配之后,executor移除之后,作业还是存在的。如果作业尝试获取executor写的中间状态数据,就需要去重新计算哪些数据。因此,spark需要一种机制来优雅地卸载executor,在移除它之前要保护它的状态。

      解决方案就是使用一个外部的shuffle服务来保存每个executor的中间写状态,这也是spark 1.2引入的特性。这个服务是一个长时间运行的进程,集群的每个节点上都会运行一个,位你的spark作业和executor服务。如果服务被启用了,那么spark executor会在shuffle write和read时,将数据写入该服务,并从该服务获取数据。这意味着所有executor写的shuffle数据都可以在executor声明周期之外继续使用。除了写shuffle文件,executor也会在内存或磁盘中持久化数据。当一个executor被移除掉时,所有缓存的数据都会消失。目前还没有有效的方案。在未来的版本中,缓存的数据可能会通过堆外存储来进行保存,就像external shuffle service保存shuffle write文件一样。

3、配置 hadoop 中 yarn 相关文件

(1)暂停 hadoop 相关服务,stop-dfs.sh 和 stop-yarn.sh

(2)暂停 standalone集群启动的shuffle service,./sbin/stop-shuffle-service.sh

(3)在$SPARK_HOME/lib目录下,定位到spark-<version>-yarn-shuffle.jar,将该jar 文件加入到所有NodeManager的classpath:$HADOOP_HOME/share/hadoop/yarn/lib 中。

(4)修改所有hadoop节点中yarn-site.xml文件,将yarn.nodemanager.aux-services设置为spark_shuffle,将yarn.nodemanager.aux-services.spark_shuffle.class设置为org.apache.spark.network.yarn.YarnShuffleService

(5)首先配置好yarn的shuffle service,然后重启hadoop 集群

4、启动 spark 作业查看是否动态资源调度 

(1)启动spark shell,添加以下参数

--conf spark.shuffle.service.enabled=true \
 --conf spark.dynamicAllocation.enabled=true \
 --conf spark.shuffle.service.port=7337 \

并启用动态资源分配,但是这里跟standalone不一样,上来不会立刻申请executor。

(2)接着执行wordcount,会尝试动态申请executor,并且申请到后,执行job,在spark web ui上,有两个executor。

(3)过了一会儿,60s过后,executor由于空闲,所以自动被释放掉了,在看spark web ui,没有executor了。