Spark内存管理解析

举报
皮皮猫 发表于 2020/05/26 22:43:16 2020/05/26
【摘要】 Spark是一个基于内存的分布式计算引擎,为了更为高效地利用内存,并减少OOM等内存问题,Spark对JVM内存模型进行了进一步的管理规划,在其之上实现了自己的内存管理模型。本文将基于spark.memory包对Spark内存管理机制进行简要探索。

Spark是一个基于内存的分布式计算引擎,为了更为高效地利用内存,并减少OOM等内存问题,SparkJVM内存模型进行了进一步的管理规划,在其之上实现了自己的内存管理模型。本文将基于spark.memory

(https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/memory/package.scala)

包对Spark内存管理机制进行简要探索。

Spark内存管理模型

与其他JVM进程类似,Spark进程的内存可以分为两部分,一是由spark.executor.memory指定的JVM堆内内存,另一部分是由spark.memory.offHeap.size指定的堆外内存。这两部分内存逻辑上由MemoryManager

(https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/memory/MemoryManager.scala)

进行统一规划与分配。MemoryManager的内存管理模式是bookkeeping式的,其并不实际负责内存的申请与释放,而是维护着进程中全局内存的使用状况,并根据一定的策略,对空闲内存进行逻辑分配,以及决定是否溢写(spill)已有数据到磁盘等。其中:

  • 堆内内存

MemoryManager将堆内内存逻辑上划分为三个主要内存区域(物理上依然是JVM堆内内存模型,占用可以任意交叉):

Reserved Memory

这一块是系统预留的内存,其大小硬编码为300MB。这意味着这300M内存是不计入Spark内存区域大小的,并且除非重新编译Spark或者设置spark.testing.reservedMemory参数,否则这块内存大小是无法更改的。不过官方仅仅只是将spark.testing.reservedMemory配置作为测试用,并不推荐在生产环境中更改。记住这块内存仅仅只是被称作“reserved”,事实上任何情况下都不能被Spark使用,但是它确定了Spark可以使用的内存分配上限。即使你想将所有的Java HeapSpark来缓存数据,reserved部分要保持空闲所以你没法这样做(其实并不是真的空闲,里面会存储很多Spark内部对象)。

User Memory

这一部分内存区域是为用户编写的Spark应用逻辑而预留的内存,其大小为:

(Java Heap - Reserved Memory) * (1.0 - spark.memory.fraction)

该部分内存的使用方式完全取决于编写Spark应用的用户。用户可以用其存储转换RDD过程中用到的中间数据结构等。比如用户重写Spark aggregation时,可以用其来存储mapPartition转换过程中用到的hash table。再次说明一下,这一块内存是User Memory,存什么和怎么存都取决于开发者,Spark不会对这一部分内存区域作限制及检查。因而,应用代码中如果忽略了分界,使用了超过该区域大小的内存,可能会导致OOM(out of memory)错误。

Spark Memory

MemoryManager实际管理的是Spark Memory这一部分内存区域,该部分内存区域大小由spark.memory.fraction控制,默认为0.6MemoryManager将该部分区域进一步划分为两个部分:

  - Storage Memory  

该部分内存可用于unroll RDD,缓存RDD,以及缓存broadcast等的传输数据。其与Execution Memory之间的边界大小由spark.memory.storageFraction控制,默认为0.5

  - Execution Memory  

该部分内存用作shuffle joins sorts以及aggregations等操作的计算内存。其由所有task共享。不过,对于各task可使用内存,MemoryManager进行了进一步控制。对于具有Ntask的进程,其确保每个task在进行spill之前,至少能获得1 / 2N的内存,但最多只能获取1 / N的内存。

  • 堆外内存

堆外内存是SparkJVM内存之外直接开辟的内存空间,用于存储经过序列化的二进制数据。由于该部分内存不经由JVM内存管理模型进行申请和释放,因而MemoryManager可以精确控制这部分内存的申请与释放,以及存储数据需要占用的内存空间大小。所以,MemoryManager将该部分内存区域简单地划分为Storage MemoryExecution Memory两部分。

  • 统一内存管理

对于Storage MemoryExecution Memory的边界划分,在Spark 1.6.0之前是由StaticMemoryManager

(https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/memory/StaticMemoryManager.scala)

控制的。其采用的是固定的划分方式,在这种划分方式下,即使其中一方有大量空闲内存,另一方也无法占用。从而,往往导致在还有大量空闲内存的情况下,依然有大量的磁盘溢写,影响Spark的性能。为了提高内存使用率,1.6.0版本的内存管理模型引入了软间隔(soft boundary)机制,使得Storage MemoryExecution Memory之间得以共享Spark Memory的空闲内存。该内存管理模式在UnifiedMemoryManager

(https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/memory/UnifiedMemoryManager.scala)

类中进行了实现。具体地:

spark.storage.storageFraction参数设定了Storage MemoryExecution Memory的基本区域,默认为0.5。该设定确定了双方各自拥有的空间范围。

双方的空间都不足时,则溢写己方内存到硬盘;若己方空间不足而对方空余时,可借用对方的空间。(存储空间不足是指不足以放下一个完整的Block)。

- Execution Memory的空间被对方占用后,可让对方将占用的部分转存到磁盘,然后"归还"借用的空间。

- Storage Memory的空间被对方占用后,无法让对方"归还",因为需要考虑执行过程中的很多因素,实现起来较为复杂。

总结

Spark的统一内存管理机制,在一定程度上提高了内存资源的利用率,降低了开发者维护及调优内存的难度。借助Spark的内存管理模型,开发者可以不再需要过多关心Spark Memory这一部分内存的内存管理。不过,开发者依然需要注意:

  • 依据实际应用场景,确定spark.memory.fraction,并且在应用开发过程中,确保使用的User Memory不超过(spark.executor.memory - 300MB) * (1.0 - spark.memory.fraction)

  • 对于需要大量存储内存或者执行内存的应用,可通过spark.memory.offHeap.enabled开启堆外内存,并适当配置堆外内存大小spark.memory.offHeap.size

  • 由于Spark对堆内内存的管理受限于JVM垃圾回收机制的不确定性以及对非序列化对象内存占用的近似估算,可能导致某一时刻实际使用内存远超预期,从而其无法完全避免内存溢出(OOM)

本文只对Spark逻辑层面的内存管理模型进行了简要介绍,对于Spark具体存储过程及执行过程中的内存操作,可基于MemoryStore

(https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/storage/memory/MemoryStore.scala)

TaskMemoryManager

(https://github.com/apache/spark/blob/master/core/src/main/java/org/apache/spark/memory/TaskMemoryManager.java)

进行更为深入的研究。

参考资源

Spark Memory Management(https://0x0fff.com/spark-memory-management/)

Apache Spark 内存管理详解(https://www.ibm.com/developerworks/cn/analytics/library/ba-cn-apache-spark-memory-management/index.html)

 


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。