首页 理论教育 如何优化Spark内存调优

如何优化Spark内存调优

时间:2023-06-29 理论教育 版权反馈
【摘要】:Storage区所能使用的堆空间的比例由spark.storage.memoryFraction指定,默认值为0.6,为了避免内存溢出的风图9-19 UnifiedMemoryManager险,使用参数spark.storage.safetyFraction来指定安全区比例,该参数的默认值为0.9,故实际可用的Storage区为堆空间的0.54;shuffle区所能使用的堆空间的比例由spark.shuffle.memoryFraction指定,默认值为0.2,为了避免内存溢出的风险,使用参数spark.shuffle.safetyFraction来指定安全区比例,该参数默认值为0.8,故实际可用的shuffle区为堆空间的0.16。如果Spark作业中有较多的RDD持久化操作,可以将spark.storage.memoryFraction的值适当提高一些,保证持久化的数据能够容纳在内存中。

如何优化Spark内存调优

Spark作为分布式计算框架,由于其优先使用内存,故对内存的管理对性能有重大影响,了解其内存管理机制及对内存的使用情况,也大大有助于程序的优化

1.Spark的内存管理机制

Spark 1.6.0之前所使用的内存管理模式由类StaticMemoryManager实现(见图9-18),而Spark 1.6.0之后所使用的内存管理模式由类UnifiedMemoryManager实现(见图9-19),当然也可以通过参数spark.memory.useLegacyMode来配置使用哪种内存管理模式。

978-7-111-55442-4-Chapter09-26.jpg

图9-18 StaticMemoryManager

Executor中对内存的使用涉及以下几点。

1)RDD存储。当对RDD调用Persist或Cache方法时,RDD的Partition会被存储到内存中。

2)Shuffle操作。Shuffle时,需要缓冲区来存储Shuffle的输出和聚合的中间结果。

3)用户代码。用户编写的代码所能使用的内存空间是整个堆空间除了上述两点之后剩下的空间。

StaticMemoryManage模式下,堆空间分为Storage区和Shuffle区。Storage区所能使用的堆空间的比例由spark.storage.memoryFraction指定,默认值为0.6,为了避免内存溢出的风

978-7-111-55442-4-Chapter09-27.jpg

图9-19 UnifiedMemoryManager

险,使用参数spark.storage.safetyFraction来指定安全区比例,该参数的默认值为0.9,故实际可用的Storage区为堆空间的0.54(0.9×0.6=0.54);shuffle区所能使用的堆空间的比例由spark.shuffle.memoryFraction指定,默认值为0.2,为了避免内存溢出的风险,使用参数spark.shuffle.safetyFraction来指定安全区比例,该参数默认值为0.8,故实际可用的shuffle区为堆空间的0.16(0.8×0.2=0.16)。如果Spark作业中有较多的RDD持久化操作,可以将spark.storage.memoryFraction的值适当提高一些,保证持久化的数据能够容纳在内存中。避免内存不够缓存所有的数据,导致数据只能写入磁盘中,降低了性能。但是如果Spark作业中的Shuffle类操作比较多,而持久化操作比较少,那么可以将spark.storage.memoryFrac-tion的值适当降低一些,而将spark.shuffle.memoryFraction的值适当提高一些,以避免shuffle过程中数据过多时内存不够用,必须溢写到磁盘上而降低性能;此外,如果发现作业由于频繁的GC导致运行缓慢(通过spark web ui可以观察到作业的GC耗时),意味着task执行用户代码的内存不够用,那么同样建议调低参数spark.storage.memoryFraction和spark.shuffle. memoryFraction的值。

UnifiedMemoryManager模式下,整个堆空间分为Spark Memory和User Memory,在Spark Memory内部又分为Storage Memory和Execution Memory,Storage Memory和Execution Memory并没有硬界限,可以相互借用空间。可以通过参数spark.memory.fraction(默认为0.75)来设置Spark Memory所占的整个堆空间的比例,剩下的空间就是User Memory(默认为1-0.75=0.25);通过spark.memory.storageFraction(默认为0.5)设置Storage Memory所占的Spark Memory的比例。根据实际程序中Cache的多少、Shuffle的多少和对象的多少等,可以调整上述各个参数来调整各个内存区的大小,进而优化程序。(www.xing528.com)

下面重点介绍UnifiedMemoryManager模式下的相关参数。

1)spark.storage.memoryFraction。参数说明:该参数用于设置RDD持久化数据在Exec-utor内存中所占的比例,默认为0.6。也就是说,默认Executor 60%的内存,可以用来保存持久化的RDD数据。根据不同的持久化策略,如果内存不够时,可能数据就不会持久化,或者数据会写入磁盘。参数调优建议:如果Spark作业中有较多的RDD持久化操作,该参数的值可以适当提高一些,保证持久化的数据能够容纳在内存中,避免内存不够缓存所有的数据,导致数据只能写入磁盘中,降低了性能。但是如果Spark作业中的Shuffle类操作比较多,而持久化操作比较少,那么这个参数的值适当降低一些比较合适。此外,如果发现作业由于频繁的GC导致运行缓慢(通过Spark web UI可以观察到作业的GC耗时),意味着task执行用户代码的内存不够用,那么同样建议调低这个参数的值。

2)spark.shuffle.memoryFraction。参数说明:该参数用于设置Shuffle过程中一个Task拉取到上个Stage的Task的输出后,进行聚合操作时能够使用的Executor内存的比例,默认为0.2。也就是说,Executor默认只有20%的内存用来进行该操作。Shuffle操作在进行聚合时,如果发现使用的内存超出了这个20%的限制,那么多余的数据就会溢写到磁盘文件中去,此时就会极大地降低性能。参数调优建议:当Spark作业中的RDD持久化操作较少、Shuffle操作较多时,建议降低持久化操作的内存占比,提高Shuffle操作的内存占比比例,避免Shuffle过程中数据过多时内存不够用,必须溢写到磁盘上,从而降低了性能。此外,如果发现作业由于频繁的GC导致运行缓慢,意味着Task执行用户代码的内存不够用,那么同样建议调低这个参数的值。

2.确定内存消耗

可以在程序中通过Cache方法将RDD Cache到内存中,然后通过WebUI的Storage页面查看该RDD占用了多少内存,或查看Driver的日志。

有很多工具也可以帮助用户了解内存的消耗,比如JVM自带的内存消耗诊断工具,如JMap、JSonsole等;第三方工具如IBM JVM Profile Tools等。

通过这些方法,可以了解各种数据结构、广播变量等对内存的占用,从而选择使用对内存更为友好的数据结构。

3.数据结构调优

详情请参阅9.3.1节的“准则八:使用优化的数据结构”。

4.序列化要持久化的RDD

详情请参阅9.3.4节。

5.垃圾回收的调优

由于Spark运行在JVM平台上,而垃圾回收是JVM的“死穴”,所以内存的调优肯定离不开垃圾回收的优化,更详细的信息请参考9.3.9节。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈