在跑Spark-On-Yarn程序时,往往会对几个参数(num-executors,executor-cores,executor-memory等)理解很模糊,从而凭感觉地去指定值,这是不符合有追求程序员信仰的。因此,搞懂它们,很有必要。
理论引导
当配置参数时,请遵循下表,并将其推荐建议牢记于心!
- Hadoop/Yarn/OS 守护进程:
当利用一个集群管理器(比如YARN)运行spark程序时,存在一些守护进程运行在后台,比如NameNode,Secondary NameNode,DataNode,ResourceManager和NodeManager。因此,当确定num-executors时,我们需要确保有足够的cores(大约每个节点一个core)维持这些守护进程的平稳运行。
- Yarn ApplicationMaster (AM):
ApplicationMaster的职责是:向ResourceManager申请资源,与NodeManager一同执行并监控container及其资源消耗。如果程序运行在Spark-On-Yarn,我们需要预留一些资源给ApplicationMaster,AM大约需要1024MB的内存和一个Executor。
- HDFS吞吐:
HDFS客户端会遇到大量并发线程的问题。 据观察,HDFS当达到全写入吞吐量时,需要每个executor执行约5个任务。 因此,最好控制每个executor中core的数目低于这个数字。
- 内存开销:
Spark-On-Yarn的每个executor的内存由以下两部分组成:
1
2
3
4 > Full memory requested to yarn per executor =
> spark-executor-memory + spark.yarn.executor.memoryOverhead
> spark.yarn.executor.memoryOverhead = Max(384MB, 7% of spark.executor-memory)
>
所以,如果我们申请了每个executor的内存为30G,那么,对我们而言,AM将得到30G + 7% × 30G约等于32G的内存。
- 执行拥有太多内存的executor会产生过多的垃圾回收延迟
- 执行过小的executor(举例而言,一个只有一核和仅仅足够内存跑一个task的executor),将会丢失在单个JVM中运行多任务的好处。
实战演练
现在,我们考虑一个10个节点的如下配置的集群,并分析不同参数设置的结果。
集群配置如下:
1 | 10个节点 |
第一种方案:Tiny executors (每个Executor一个Core)
1 | '--num-executors' = '该方案下,每个executor配置一个core' |
分析
当一个executor只有一个core时,正如我们上面分析的,我们可能不能发挥在单个JVM上运行多任务的优势。此外,共享/缓存变量(如广播变量和累加器)将复制到节点的每个core,这里是16次。并且,我们没有为Hadoop / Yarn守护进程留下足够的内存开销,我们也没有计入ApplicationManager。因此,这不是一个好的方案!
第二种方案:Fat executors (每个节点一个Executor)
1 | '--num-executors' = '该方案下,一个executor独占一个节点' |
分析
每个executor独占16个核心,则ApplicationManager和守护程序进程则无法分配到core,并且,HDFS吞吐量会受到影响,导致过多的垃圾结果。 同样地,该方案不好!
第三种方案:Balance between Fat (vs) Tiny
根据上面讨论的建议:
基于上述的建议,我们给每个executor分配5个core => – executor-cores = 5 (保证良好的HDFS吞吐)
每个节点留一个core给Hadoop/Yarn守护进程 => 每个节点可用的core的数目 = 16 - 1 = 15
所以,集群中总共可用的core的数目是 15 * 10 = 150
可用的executor的数目 = (总的可用的core的数目 / 每个executor的core的数目)= 150 / 5 = 30
留一个executor给ApplicationManager => –num-executors = 29
每个节点的executor的数目 = 30 / 10 = 3
每个executor的内存 = 40GB / 3 = 13GB (这里假设总64G内存拿出40G来分配给spark使用)
计算堆开销 = 7% * 13GB = 1GB。因此,实际的 –executor-memory = 13 -1 = 12GB
因此,推荐的配置如下:29 executors, 12GB memory each and 5 cores
分析
很明显,第三种方案在Fat vs Tiny 两种方案中找到了合适的平衡点。毋庸置疑,它实现了Fat executor的并行性和Tiny executor的最佳吞吐量!
结论
当为spark程序配置运行参数的时候,应谨记一些推荐事项:
- 为Yarn的Application Manager预留资源
- 我们应该如何为Hadoop / Yarn / OS deamon进程节省一些cores
- 学习关于spark-yarn-memory-usage
另外,检查并分析了配置这些参数的三种不同方法:
- Tiny Executors - 每个executor配置一个core
- Fat Executors - 每个executor独占一个节点
- 推荐方案 - 基于建议项的Tiny(Vs)Fat的合适的平衡
–num-executors, –executor-cores and –executor-memory 这三个参数在spark性能中扮演很重要的角色,它们控制着spark程序获得的CPU和内存的资源。因此对于用户来说,很有必要理解如何去配置它们。