[Spark] Spark内存管理

高层视图

[Spark] Spark内存管理_第1张图片

堆内内存 On-heap Memory
  • Executor内存管理建立在JVM的内存管理之上
  • executor-memory指定Executor内存
  • 并不能准确记录实际可用的堆内内存
堆外内存 Off-heap Memory
  • Spark通过JDK Unsafe API引入了堆外内存,用于存储序列化后的二进制数据
  • 通过配置 spark.memory.offHeap.enabled 参数启用,并由spark.memory.offHeap.size 参数设定堆外空间大小

堆内内存

就留个图方便复习的时候回忆,详细内容还写个屁啊, 直接看[这篇文章]
(https://www.jianshu.com/p/0f0...

[Spark] Spark内存管理_第2张图片

RDD 持久化缓存

RDD持久化

RDD 的持久化由 Spark 的 Storage 模块负责,实现了 RDD 与物理存储的解耦合。
Storage 模块负责管理 Spark 在计算过程中产生的数据,将那些在内存或磁盘、在本地或远程存取数据的功能封装了起来。在
具体实现时 Driver 端和 Executor 端的 Storage 模块构成了主从式的架构,即 Driver 端的 BlockManager 为 Master,Executor 端的 BlockManager 为 Slave。Storage 模块在逻辑上以 Block 为基本存储单位,RDD 的每个 Partition 经过处理后唯一对应一个 Block(BlockId 的格式为 rdd_RDD-ID_PARTITION-ID )。Master 负责整个 Spark 应用程序的 Block 的元数据信息的管理和维护,而 Slave 需要将 Block 的更新等状态上报到 Master,同时接收 Master 的命令,例如新增或删除一个 RDD。
[Spark] Spark内存管理_第3张图片

RDD缓存

RDD 在缓存到存储内存之前,Partition 中的数据一般以迭代器Iterator的数据结构来访问。通过 Iterator 可以获取分区中每一条序列化或者非序列化的数据项(Record),这些 Record 的对象实例在逻辑上占用了 JVM 堆内内存的 User Memory 部分的空间,同一 Partition 的不同 Record 的空间并不连续
RDD 在缓存到存储内存之后,Partition 被转换成 Block,Record 在堆内或堆外存储内存中占用一块连续的空间。将Partition由不连续的存储空间转换为连续存储空间的过程,Spark称之为"展开"(Unroll)。
每个 Executor 的 Storage 模块用一个链式 Map 结构(LinkedHashMap)来管理堆内和堆外存储内存中所有的 Block 对象的实例,对这个 LinkedHashMap 新增和删除间接记录了内存的申请和释放。
[Spark] Spark内存管理_第4张图片

缓存的淘汰和落盘

由于同一个 Executor 的所有的计算任务共享有限的存储内存空间,当有新的 Block 需要缓存但是剩余空间不足且无法动态占用时,就要对 LinkedHashMap 中的旧 Block 进行淘汰(Eviction),而被淘汰的 Block 如果其存储级别中同时包含存储到磁盘的要求,则要对其进行落盘(Drop),否则直接删除该 Block。

存储内存的淘汰规则为:

  1. 被淘汰的旧 Block 要与新 Block 的 MemoryMode 相同,即同属于堆外或堆内内存
  2. 新旧 Block 不能属于同一个 RDD,避免循环淘汰
  3. 旧 Block 所属 RDD 不能处于被读状态,避免引发一致性问题
  4. 遍历 LinkedHashMap 中 Block,按照最近最少使用(LRU)的顺序淘汰,直到满足新 Block 所需的空间。其中 LRU 是 LinkedHashMap 的特性。

落盘的流程则比较简单,如果其存储级别符合_useDisk 为 true 的条件,再根据其_deserialized 判断是否是非序列化的形式,若是则对其进行序列化,最后将数据存储到磁盘,在 Storage 模块中更新其信息。

你可能感兴趣的:(spark)