Spark任务的core,executor,memory资源配置方法

Spark任务的core,executor,memory资源配置方法

1、背景

执行Spark任务,资源分配是很重要的一方面。如果配置不准确,Spark任务将耗费整个集群的机缘导致其他应用程序得不到资源。

怎么去配置Spark任务的executors,cores,memory,有如下几个因素需要考虑:

  • 数据量
  • 任务完成时间点
  • 静态或者动态的资源分配
  • 上下游应用

2、Spark应用当中术语的基本定义:

  • Partitions : 分区是大型分布式数据集的一小部分。 Spark使用分区来管理数据,这些分区有助于并行化数据处理,并且使executor之间的数据交换最小化
  • Task:任务是一个工作单元,可以在分布式数据集的分区上运行,并在单个Excutor上执行。并行执行的单位是任务级别。单个Stage中的Tasks可以并行执行
  • Executor:在一个worker节点上为应用程序创建的JVM,Executor将巡行task的数据保存在内存或者磁盘中。每个应用都有自己的一些executors,单个节点可以运行多个Executor,并且一个应用可以跨多节点。Executor始终伴随Spark应用执行过程,并且以多线程方式运行任务。spark应用的executor个数可以通过SparkConf或者命令行 –num-executor进行配置
  • Cores:CPU最基本的计算单元,一个CPU可以有一个或者多个core执行task任务,更多的core带来更高的计算效率,Spark中,cores决定了一个executor中并行task的个数
  • Cluster Manager:cluster manager负责从集群中请求资源

3、cluster模式执行的Spark任务包含了如下步骤:

  1. driver端,SparkContext连接cluster manager(Standalone/Mesos/Yarn)
  2. Cluster Manager在其他应用之间定位资源,只要executor执行并且能够相互通信,可以使用任何Cluster Manager
  3. Spark获取集群中节点的Executor,每个应用都能够有自己的executor处理进程
  4. 发送应用程序代码到executor中
  5. SparkContext将Tasks发送到executors

以上步骤可以清晰看到executors个数和内存设置在spark中的重要作用。

4、spark任务的最佳方式

以下将尝试理解优化spark任务的最佳方式:

  1. 静态分配:配置值从spark-submit中体现
  2. 动态分配:从数据量和计算需求上衡量资源需求,并在使用后释放掉,这样可以让其他应用重复利用资源

4.1、静态分配

以下按不同例子讨论验证不同参数和配置组合

例子1
硬件资源: 6 节点,每个节点16 cores, 64 GB 内存
每个节点在计算资源时候,给操作系统和Hadoop的进程预留1core,1GB,所以每个节点剩下15个core和63GB
内存。
core的个数,决定一个executor能够并发任务的个数。所以通常认为,一个executor越多的并发任务能够得到更好的性能,但有研究显示一个应用并发任务超过5,导致更差的性能。所以core的个数暂设置为5个。
5个core是表明executor并发任务的能力,并不是说一个系统有多少个core,即使我们一个CPU有32个core,也设置5个core不变。
executor个数,接下来,一个executor分配 5 core,一个node有15 core,从而我们计算一个node上会有3 executor(15 / 5),然后通过每个node的executor个数得到整个任务可以分配的executors个数。
我们有6个节点,每个节点3个executor,6 × 3 = 18个executors,额外预留1个executor给AM,最终要配置17个executors。
最后spark-submit启动脚本中配置 –num-executors = 17
memory,配置每个executor的内存,一个node,3 executor, 63G内存可用,所以每个executor可配置内存为63 / 3 = 21G
从Spark的内存模型角度,Executor占用的内存分为两部分:ExecutorMemory和MemoryOverhead,预留出MemoryOverhead的内存量之后,才是ExecutorMemory的内存。
MemoryOverhead的计算公式: max(384M, 0.07 × spark.executor.memory)

因此 MemoryOverhead值为0.07 × 21G = 1.47G > 384M

最终executor的内存配置值为 21G – 1.47 ≈ 19 GB

至此, Cores = 5, Executors= 17, Executor Memory = 19 GB


例子2
硬件资源:6 node,32 core / node ,64G RAM / node
core个数:5,与例子1中描述具体原因相同
每个node的executor个数是 32 / 5 = 6
executor总个数: 6 node × 6 executor - 1 (AM) = 35
executor memory:
每个node的内存 = 63G(1G留给系统应用) / 6 ≈ 10
MemoryOverhead = 0.07 × 10G = 700M 约等于 1G
ExecutorMemory = 10 G - 1 G = 9 GB

最终 Cores = 5, Executors = 5, Executor Memory = 9 GB


例子3
硬件资源: 6 节点,每个节点16 cores, 64 GB 内存
例子1和2的场景,都是从固定的core数量,计算executor和memory的数量。
基于例子1,假设memory不需要19G,而仅需要10G内存就足够数据计算,此时core, executor,memory按如下计算方式:
core个数据:5
每个node的executor个数:15 / 3 = 5
按照例子1计算方式,这个阶段的内存使用21G,除去MemoryOverhead的内存占用,剩下19G。当我们10G内存就足够的场景下,不能使用 63G / 10G = 6个executor。因为 6 exector × 5 core = 30 core,每个node要有30core,而例子1硬件配置是16core。这样我们就需要修改每个executor的core配置。

接下来,将core的个数从5改为3,每个node有5个executor,一共应该有 5 executor * 6 node - 1(AM占用的core) = 29 ,memory则 63G / 5 ≈ 12
MemoryOverhead = 0.07 × 12G = 840M 约等于 1G
ExecutorMemory = 12 G - 1 G = 11 GB

最终 Core = 3,Executor = 29,Executor Memory = 11G

4.2、动态分配

如果采用动态分配策略,executer的个数上限是无穷大。这就意味着Spark任务在需要资源的情况下,会占用到集群左右资源,集群中会有其他应用也需要资源运行,所以我们需要在集群层面上对core进行分配控制。

这就意味着我们在基于用户访问基础上,在基于YARN的任务中进行分配core,我们创建一个spark_user,分配min max的core个数,这些core从YARN中剥离,区别于其他基于YARN调度应用(例如Hadoop等)

为了理解动态资源分配,首先需要了解一些属性配置项:

spark.dynamicAllocation.enabled : 设置为true,意味着我们不关心executor的个数,考虑用到动态资源分配策略,在stage阶段会有一下区别:

  • 以多少个executor启动Spark任务?

spark.dynamicAllocation.initialExecutors:初始化executor个数

  • 怎样动态控制executor的个数?

我们通过spark-submit的方式初始化executor个数,根据负载情况,任务在min(spark.dynamicAllocation.minExecutors)和max(spark.dynamicAllocation.maxExecutors)之间决定executor个数。

  • 什么时候获取一个新的executor和放弃一个executor

spark.dynamicAllocation.schedulerBacklogTimeout :依靠这个参数,决定我们什么时候获取一个新的executor,每轮任务executor个数较前一轮将逞指数增长,比如第一轮1个executor,后续添加2,4,8个executor的方式,在某些特定场景下,将使用max(spark.dynamicAllocation.maxExecutors)个executor。
spark.dynamicAllocation.executorIdleTimeout :executor空闲的时间,超时之后,将executor移除

<think>好的,用户想了解如何在Spark中确定Executor的核心数分配。我需要根据提供的引用资料来整理回答。首先,用户提供的引用中有四个相关的内容,涉及Executorcores、内存配置以及性能调优的建议。 先回忆一下Spark的基本架构。每个Executor是一个JVM进程,负责运行task。核心数(cores)决定了Executor并行执行task的能力。每个core同一时间只能处理一个task,所以cores越多,并行能力越强。但配置过高可能导致资源竞争,过少则可能资源利用不足。 根据引用[4],参数`spark.executor.cores`设置每个Executor的CPU core数量,直接影响task的并行能力。需要结合集群资源和任务特性来调整。比如,如果每个Executor有3个core,就能同时跑3个task。 然后看引用[3],提到Tiny executors方案,每个Executor配1个core。这种情况下,总Executor数等于集群总core数。比如16个节点,每个节点16 core,总共有160 core,那么Executor数量就是160,每个1 core,内存4GB。但可能这种配置不适合需要较高并行度的任务,因为每个Executor只能处理一个task,可能影响效率。 引用[1]中的例子是每个Executor配3 core,共5个Executor,内存13GB。这说明实际配置需要权衡core数和内存,同时考虑总资源的情况。比如,总核心数是3*5=15,可能集群总core数为15或更高,允许这样的分配。 引用[2]建议`spark.sql.shuffle.partitions`设置为总core数的2~3倍。这说明并行度与总cores相关,而总cores由`num-executors` * `executor-cores`决定。所以配置cores时需要考虑后续的并行参数。 接下来需要整理配置时的考虑因素: 1. **总集群资源**:每个节点的core数和内存,总节点数。例如,每个节点有16 cores和64GB内存,总共有10个节点,总cores是160,总内存640GB。 2. **Executorcores选择**: - 每个Executorcore数通常在1到5之间。太多会导致内存不足,GC压力大;太少则并行度低。 - 例如,如果选择3 cores,每个Executor内存13GB(引用[1]),那么每个Executor的内存分配需足够每个task使用,避免OOM。 3. **内存分配**:每个Executor的内存需要分配给堆内存、堆外内存、以及Spark内部开销。例如,内存分为`executor-memory`,其中堆外内存可能需要通过参数调整,如`spark.executor.memoryOverhead`。如果配置13GB,可能实际可用堆内存为13 - 1(overhead)=12GB左右。 4. **Executor数量计算**: - `num-executors` = (总集群cores / 每个Executorcores) - 预留的cores(比如给ApplicationMaster和其他进程)。 - 例如,总cores 160,每个Executor 3 cores,预留1 core,则`num-executors`=(160-1)/3≈53,但实际可能需要根据节点分布调整,比如每个节点分配固定数量的Executors,避免跨节点资源竞争。 5. **性能调优考虑**: - 数据本地性和任务调度:较多的Executors可能提升数据本地性,但管理开销增加。 - Shuffle操作:需要足够的并行度,调整shuffle partitions参数。 - 避免资源浪费:确保cores和内存的平衡,避免内存不足或cores闲置。 另外,用户提供的示例中,引用[3]提到Tiny executors可能适合某些场景,但通常推荐使用适量cores的配置,比如每个Executor 3-5 cores,以平衡并行度和资源利用率。 总结步骤可能包括: 1. 确定集群总资源。 2. 根据任务类型(CPU密集型或内存密集型)决定每个Executorcores和内存。 3. 计算可行的Executors数量,考虑预留资源。 4. 调整相关参数如shuffle partitions。 5. 测试并监控性能,进行优化调整。 需要确保回答结构清晰,分步骤说明,并引用相关资料中的例子和参数建议。同时,生成相关问题,可能涉及优化方法、内存配置、参数调优等。</think>在Spark中合理配置Executor核心数(cores)是性能调优的关键环节,需综合考虑集群资源、任务特性和并行需求。以下是具体配置方法和计算步骤: --- ### **一、核心参数关系** 1. **总资源公式** $$总核心数 = num\text{-}executors \times executor\text{-}cores$$ 需确保总核心数不超过集群可用核心数(预留1-2个核心给系统进程)[^3]。 2. **内存分配公式** $$executor\text{-}memory = \frac{节点总内存}{每个节点的executor数量}$$ 需预留10%内存给操作系统和Spark管理开销[^1]。 --- ### **二、配置步骤** 1. **确定集群资源** - 假设集群有10个节点,每个节点16核心、64GB内存。 2. **选择单个Executorcores** - **推荐范围**:3-5 cores/executor[^1] - **过高风险**:内存不足导致GC时间长;**过低风险**:并行度不足。 - 示例选择3 cores/executor。 3. **计算Executor数量** $$num\text{-}executors = \lfloor \frac{总核心数 - 预留核心}{executor\text{-}cores} \rfloor$$ 若预留2核心: $$num\text{-}executors = \lfloor \frac{10 \times 16 - 2}{3} \rfloor = 52$$ 4. **计算Executor内存** $$executor\text{-}memory = \frac{节点内存}{每个节点的executor数量} \times 0.9$$ 每个节点运行5 executors(总executors=52,约每个节点5-6个): $$executor\text{-}memory = \frac{64GB}{5} \times 0.9 \approx 11.5GB$$ 实际配置为`--executor-memory 11g`[^1]。 --- ### **三、配置优化建议** 1. **CPU密集型任务**:增加`executor-cores`(4-5 cores),减少executor数量。 2. **内存密集型任务**:降低`executor-cores`(2-3 cores),提升单个executor内存。 3. **动态分配**:启用`spark.dynamicAllocation.enabled`自动调整资源[^2]。 4. **Shuffle调优**:设置`spark.sql.shuffle.partitions`为总核心数的2-3倍[^2]。 --- ### **四、示例配置** ```bash spark-submit \ --num-executors 52 \ --executor-cores 3 \ --executor-memory 11g \ --conf spark.sql.shuffle.partitions=300 \ ... ``` ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值