Spark内存资源分配——spark.executor.memory等参数的设置方法

概述

基于论坛上一些关于spark内存设置的文章,我对一个项目中实际运行的任务进行了内存参数分析和优化。如果要了解更多详细设置原理,可见文末的参考文章链接。
已知内存分配存在通过用户提交的参数设置进行静态分配,和yarn进行动态分配两种,所以本文对两种状况都根据实际场景进行了分析。

资源详情

配置spark的内存参数,首先要基于集群资源的情况。本例的机器情况:一共8台机器,即8个Node。核心数:32 core / node;内存资源:50.8GB RAM/ node。
每个Node在计算的时候,给操作系统和Hadoop的进程预留2core,2.8GB,所以每个节点剩下28个core和48GB内存。

任务A——推断动态分配内存的过程

发现任务提交的参数设置为:
executor-memory=8g;num-executors=10;executor-cores=3。考虑到有MemoryOverhead,发现任务有参数将其设置为1G。(默认值是max(384M, 0.07 × spark.executor.memory))
因此按参数配置,本任务占用总内存为(8+1)10=90gb;核心数为310=30。可见一定没有占满,那么系统会基于memory动态分配core和executor-num。

executor个数:num-executors

因为一个executor其实可以跨node运行,因此用总可用内存数除以每个executor的内存数,可得总计num-executors=320/8=40,考虑有可能有1GB的MemoryOverhead,则num-executors应为320/9≈36,所以系统可能会动态分配36~40个executor。
也可能Yarn比我们设想的还要狠,给其他应用预留的空间更少,那么极限情况下把所有可用内存都给这个应用,那么最大的num-executors=(50.88)/8≈50,考虑MemoryOverhead,则num-executors应为(50.88)/9≈45。
最终,可以猜测Yarn动态分配的Executor个数在36~50个之间,40左右较为合理。
通过查看web页面的某个stage的执行计划,可以发现确实是40个executor。
Yarn中某个Stage的Executor分配情况

core的个数

本参数决定一个executor能够并发任务的个数。所以通常认为,一个executor越多的并发任务能够得到更好的性能。但有研究显示一个应用并发任务超过5,导致更差的性能。
目前已知共有40个executor,8个node,则一个Node平均5个executor。同时一个Node30个核(去掉预留的2个),那么如果动态分配,可能最多给每个Executor动态分配30/5=6个Core。
从Yarn的总Core分配界面可以看到差不多是这样。当然,如果有更好的方法从WEB界面的Spark ApplicationMaster里查看到core的数量,欢迎分享。
Yarn的Node详情

driver-memory大小

driver运行内存,默认值512m,一般2-6G。目前来看该参数对任务运行没有太大的影响,本案例中的设置值为4g。即,driver-memory=4g

————后来实际运行任务时,查看执行日志可以发现,这个任务总在报内存不足的错误,因此考虑设置合理的静态内存分配参数,把executor的内存调大,这就可以参考下面一个任务的设置过程。
修改之后,Yarn上的资源分配情况,可以看出确实和新设置的参数很符合,即1个Executor占20G内存。在这里插入图片描述

任务B——静态分配内存参数的设置过程

因为该任务经常报超内存的错误,所以先设置memory大小。

memory大小

配置每个executor的内存,一个node,48G内存可用。考虑到集群还会有其他任务运行,所以给其他任务留8GB,所以设置每个 executor可配置内存为40GB。这也意味着一个node1个executor。
从Spark的内存模型角度,Executor占用的内存分为两部分:ExecutorMemory和MemoryOverhead,预留出MemoryOverhead的内存量之后,才是ExecutorMemory的内存。
MemoryOverhead的计算公式: max(384M, 0.07 × spark.executor.memory)
因此 MemoryOverhead = 0.07 × 40G = 2.8G=2867MB 约等于3G > 384M
最终executor的内存配置值为 40G – 3 =37 GB
因此设置:executor-memory = 37 GB;spark.executor.memoryOverhead=3*1024=3072

core的个数

决定一个executor能够并发任务的个数。所以通常认为,一个executor越多的并发任务能够得到更好的性能。在本次设置中,理论上来说,由于1个node只有1个executor,所以可以用24个core。但有研究显示一个应用并发任务超过5,导致更差的性能。
所以core的个数暂设置为5个。
5个core是表明executor并发任务的能力,并不是说一个系统有多少个core,即使我们一个CPU有32个core,也设置5个core不变。
因此设置:executor-cores=5

executor个数

因为已经设置好1个node只有1个executor,所以,之后通过每个node的executor个数,可以得到整个任务可以分配的executors个数。
我们有8个节点,每个节点1个executor,8 × 1 = 8个executors,额外预留1个executor给AM,最终要配置7个executors。
因此设置:num-executors=7

driver-memory大小

driver运行内存,默认值512m,一般2-6G。目前来看该参数对任务运行没有太大的影响,因此就设置4g。
因此设置:driver-memory=4g

参考文章

对参数设置讲的很细的一篇,本文重点参考:Spark任务的core,executor,memory资源配置方法

对Spark Executor Memory做系统讲解,特别是讲到内存分为执行内存和存储内存两部分。还介绍了一些别的参数:如何设置Spark Executor Memory的大小

延申的内存调优,即对shuffle过程的参数调优,这个本例没有用到,有兴趣的话可以尝试一下:Spark学习(五)Spark Shuffle及内存分配

  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Spark性能优化指南的基础篇主要包括开发调优和资源调优两个方面,其中设置参数是资源调优的重要内容。 在开发调优方面,需要注意以下几点: 1. 避免使用不必要的shuffle操作,因为shuffle操作会导致数据的重新分区和网络传输,从而影响性能。 2. 尽量使用RDD的转换操作,而不是行动操作,因为行动操作会触发计算并返回结果,而转换操作只是定义了计算过程,不会立即执行。 3. 使用广播变量来减少数据的传输,广播变量可以将一个只读变量缓存到每个节点上,避免重复传输。 在资源调优方面,需要注意以下几点: 1. 设置合适的内存分配比例,可以通过调整spark.driver.memoryspark.executor.memory参数来实现。 2. 设置合适的并行度,可以通过调整spark.default.parallelism参数来实现。 3. 设置合适的序列化方式,可以通过调整spark.serializer和spark.kryoserializer.buffer.max参数来实现。 4. 设置合适的存储级别,可以通过调整RDD的存储级别来实现。 总之,通过合理设置参数和优化代码,可以提高Spark的性能和效率。 ### 回答2: Spark性能优化是一个非常复杂的过程,它通常被视为一项高级技能。在Spark的使用过程中,开发调优和资源调优都是非常重要的,这篇文章将重点介绍一些基础篇的内容,包括开发调优和资源调优中的设置参数。 首先,我们来看一下开发调优。在Spark中,开发者需要注意一些代码实践,以确保代码的性能最优。以下是一些开发调优的最佳实践: 1.避免使用lambda表达式,特别是在数据集或数据框的操作中。虽然lambda表达式在编码过程中非常方便,但它们往往会导致不必要的对象和内存分配,从而降低了性能。 2.尽可能地使用原语而不是高级API。原语比高级API实现更快,同时也具有更多的控制力。例如,使用RDD代替DataFrame可能会带来更好的性能。 3.使用宽依赖(例如reduceByKey)代替窄依赖(例如groupByKey)。宽依赖通过并行化来提高执行效率,而窄依赖则依赖于串行执行。 4.尽可能的避免使用全局变量或静态变量,因为它们会使Spark的并行性降低并导致性能下降。 接下来,我们将讨论资源调优中设置参数的相关内容。在Spark的资源调优中,设置参数是非常重要的,因为它们可以帮助我们优化内存、CPU、网络等资源的使用,从而实现更好的性能。 1.调整executor内存大小。这是最基本的调优步骤,executor内存越大,Spark可以处理的数据量就越大,从而带来更好的性能。通常,设置executor内存为节点可用内存大小的三分之一是比较合理的。 2.调整shuffle分区数。调整shuffle分区数对于网络和I/O使用非常重要。通常情况下,每个CPU内核的shuffle分区数应该大约为2-3个。 3.调整并行度。并行度是指在Spark上运行的任务和数据的并发程度。较高的并行度可以提高Spark的性能。通常情况下,并行度应该设置为CPU内核数的两倍以上。 4.调整序列化格式。可以通过改变序列化格式来提高性能,比如使用Kryo而不是默认的Java序列化格式。Kryo在序列化大型对象时比Java序列化更快。 综上所述,开发调优和资源调优是优化Spark性能的两个非常关键的方面。通过遵循最佳实践和设置合适的参数,可以使Spark应用程序在性能和资源使用方面发挥出最大的潜力,提高生产力和成果。 ### 回答3: Spark是一种强大的数据处理框架,需要高效的性能来完成各种任务。本篇文章将介绍一些关键的Spark性能优化指南——基础篇,包括开发调优、资源调优和设置参数。 开发调优 1. 使用高效的算法和数据结构 不同的算法和数据结构对于Spark作业的性能有着巨大的影响。了解每个任务所需的计算复杂度和数据大小,并对其进行优化是非常重要的。 2. 将代码逻辑转换为RDD操作 RDD操作是Spark的核心概念之一。将代码逻辑转换为RDD操作可以大幅提升Spark的性能表现。因此,应该尽量使用Spark提供的各种高级API来进行开发,而不是去编写过于冗长的自定义代码。 3. 减小内存开销 为了让Spark的性能保持稳定,开发者应该尽量减小内存占用。这包括压缩数据、使用序列化器等等。 资源调优 1. 配置适当的并行度 Spark作业的并行度决定了任务能够同时处理的数据量。错误的并行度设置可能会导致任务成功率降低或者资源利用不充分的情况。因此,开发者需要通过多次试验来找到适合自己任务的并行度。 2. 调整JVM内存 JVM内存的大小对于Spark作业的性能有着很大的影响。如果JVM内存设置过小,可能会导致堆的内存不足。反之,如果设置过大,可能会导致垃圾回收时间变长。因此,开发者应该根据任务的需求来调整JVM内存的大小。 设置参数 1. 启用动态分区(spark.sql.shuffle.partitions) 设置动态分区可以让Spark自动根据数据量来设置操作的分区数,从而提高作业性能。 2. 启用动态分配内存spark.shuffle.service.enabled) Spark默认会预留50%的堆内存用于垃圾回收。但是对于内存资源较为紧缺的情况,这可能会影响到作业的性能。开启动态分配内存可以让Spark自动调整内存的使用率,优化作业的性能。 总结 本篇文章介绍了Spark性能优化的基础篇,包括开发调优、资源调优和参数设置。这些方法可以极大地提高Spark作业的性能表现。然而,Spark的性能优化是一个细节精益工程,需要开发者不断进行优化和调整。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值