主页 > 新闻资讯 > 大数据学习:Spark内存管理

大数据学习:Spark内存管理

作者:张老师 浏览次数: 2021-02-01 17:14
Spark基于内存计算的方式,带来了整体计算性能的成倍提升,但是同时,想要保证Spark运行的稳定与高效,对于内存的管理和优化,是非常考验开发人员的能力的。今天的大数据学习分享,我们就主要来讲讲Spark内存管理相关的内容。
 
大数据学习:Spark内存管理

在执行Spark的应用程序时,Spark集群会启动Driver和Executor两种JVM进程,前者为主控进程,负责创建Spark Context,提交Spark作业(Job),并将作业转化为计算任务(Task),在各个Executor进程间协调任务的调度,后者负责在工作节点上执行具体的计算任务,并将结果返回给Driver,同时为需要持久化的RDD提供存储功能。由于Driver的内存管理相对来说较为简单,这里主要对Executor的内存管理进行分析,下文中的Spark内存均特指Executor的内存。
 
堆内和堆外内存规划
 
作为一个JVM进程,Executor的内存管理建立在JVM的内存管理之上,Spark对JVM的堆内(On-heap)空间进行了更为详细的分配,以充分利用内存。同时,Spark引入了堆外(Off-heap)内存,使之可以直接在工作节点的系统内存中开辟空间,进一步优化了内存的使用。
 
堆内内存受到JVM统一管理,堆外内存是直接向操作系统进行内存的申请和释放
 
1、堆内内存
 
堆内内存的大小,由Spark应用程序启动时的–executor-memory或spark.executor.memory参数配置。Executor内运行的并发任务共享JVM堆内内存,这些任务在缓存RDD数据和广播(Broadcast)数据时占用的内存被规划为存储(Storage)内存,而这些任务在执行Shuffle时占用的内存被规划为执行(Execution)内存,剩余的部分不做特殊规划,那些Spark内部的对象实例,或者用户定义的Spark应用程序中的对象实例,均占用剩余的空间。不同的管理模式下,这三部分占用的空间大小各不相同。
 
Spark对堆内内存的管理是一种逻辑上的"规划式"的管理,因为对象实例占用内存的申请和释放都由JVM完成,Spark只能在申请后和释放前记录这些内存,我们来看其具体流程:
 
申请内存流程如下:
 
①Spark在代码中new一个对象实例;
 
②JVM从堆内内存分配空间,创建对象并返回对象引用;
 
③Spark保存该对象的引用,记录该对象占用的内存。
 
释放内存流程如下:
 
①Spark记录该对象释放的内存,删除该对象的引用;
 
②等待JVM的垃圾回收机制释放该对象占用的堆内内存。
 
我们知道,JVM的对象可以以序列化的方式存储,序列化的过程是将对象转换为二进制字节流,本质上可以理解为将非连续空间的链式存储转化为连续空间或块存储,在访问时则需要进行序列化的逆过程——反序列化,将字节流转化为对象,序列化的方式可以节省存储空间,但增加了存储和读取时候的计算开销。
 
对于Spark中序列化的对象,由于是字节流的形式,其占用的内存大小可直接计算,而对于非序列化的对象,其占用的内存是通过周期性地采样近似估算而得,即并不是每次新增的数据项都会计算一次占用的内存大小,这种方法降低了时间开销但是有可能误差较大,导致某一时刻的实际内存有可能远远超出预期。
 
此外,在被Spark标记为释放的对象实例,很有可能在实际上并没有被JVM回收,导致实际可用的内存小于Spark记录的可用内存。所以Spark并不能准确记录实际可用的堆内内存,从而也就无法完全避免内存溢出(OOM,Out of Memory)的异常。
 
虽然不能精准控制堆内内存的申请和释放,但Spark通过对存储内存和执行内存各自独立的规划管理,可以决定是否要在存储内存里缓存新的RDD,以及是否为新的任务分配执行内存,在一定程度上可以提升内存的利用率,减少异常的出现。
 
2、堆外内存
 
为了进一步优化内存的使用以及提高Shuffle时排序的效率,Spark引入了堆外(Off-heap)内存,使之可以直接在工作节点的系统内存中开辟空间,存储经过序列化的二进制数据。
 
堆外内存意味着把内存对象分配在Java虚拟机的堆以外的内存,这些内存直接受操作系统管理(而不是虚拟机)。这样做的结果就是能保持一个较小的堆,以减少垃圾收集对应用的影响。
 
利用JDK Unsafe API(从Spark 2.0开始,在管理堆外的存储内存时不再基于Tachyon,而是与堆外的执行内存一样,基于JDK Unsafe API实现),Spark可以直接操作系统堆外内存,减少了不必要的内存开销,以及频繁的GC扫描和回收,提升了处理性能。
 
堆外内存可以被精确地申请和释放(堆外内存之所以能够被精确的申请和释放,是由于内存的申请和释放不再通过JVM机制,而是直接向操作系统申请,JVM对于内存的清理是无法准确指定时间点的,因此无法实现精确的释放),而且序列化的数据占用的空间可以被精确计算,所以相比堆内内存来说降低了管理的难度,也降低了误差。
 
在默认情况下堆外内存并不启用,可通过配置spark.memory.offHeap.enabled参数启用,并由spark.memory.offHeap.size参数设定堆外空间的大小。除了没有other空间,堆外内存与堆内内存的划分方式相同,所有运行中的并发任务共享存储内存和执行内存。
 
关于大数据学习,Spark内存管理,以上就为大家做了简单的介绍了。Spark内存管理,整体来说分为堆内内存和堆外内存,但是其中的诸多细节,还需要更细致地去理解。成都加米谷大数据,专业大数据培训机构,大数据开发、数据分析挖掘,零基础班本月正在招生中,课程大纲及试学视频可联系客服领取!
热点排行
推荐文章
立即申请>>