Spark 做为一个以擅长内存计算为优点的计算引擎,内存管理方案是其很是重要的模块; Spark的内存能够大致归为两类:execution和storage,前者包括shuffles、joins、sorts和aggregations所需内存,后者包括cache和节点间数据传输所需内存;在Spark 1.5和以前版本里,二者是静态配置的,不支持借用,spark1.6 对内存管理模块进行了优化,经过内存空间的融合,消除以上限制,提供更好的性能。官方网站只是要求内存在8GB之上便可(Impala推荐要求机器配置在128GB), 但spark job运行效率主要取决于:数据量大小,内存消耗,内核数(肯定并发运行的task数量)git
目录:github
- 基础知识
- spark1.5- 内存管理
- spark1.6 内存管理
基本知识:算法
- on-heap memory:Java中分配的非空对象都是由Java虚拟机的垃圾收集器管理的,也称为堆内内存。虚拟机会按期对垃圾内存进行回收,在某些特定的时间点,它会进行一次完全的回收(full gc)。完全回收时,垃圾收集器会对全部分配的堆内内存进行完整的扫描,这意味着一个重要的事实——这样一次垃圾收集对Java应用形成的影响,跟堆的大小是成正比的。过大的堆会影响Java应用的性能
- off-heap memory:堆外内存意味着把内存对象分配在Java虚拟机的堆之外的内存,这些内存直接受操做系统管理(而不是虚拟机)。这样作的结果就是能保持一个较小的堆,以减小垃圾收集对应用的影响
- LRU Cache(Least Recently Used):LRU能够说是一种算法,也能够算是一种原则,用来判断如何从Cache中清除对象,而LRU就是“近期最少使用”原则,当Cache溢出时,最近最少使用的对象将被从Cache中清除
- spark 源码: https://github.com/apache/spark/releases
- scale ide for Intellij : http://plugins.jetbrains.com/plugin/?id=1347
Spark1.5- 内存管理:apache
- 1.6 版本引入了新的内存管理方案,配置参数: spark.memory.useLegacyMode 默认 false 表示使用新方案,true 表示使用旧方案, SparkEnv.scala 源码 以下图:

- 在staticMemoryManager.scala 类中查看构造类及内存获取定义

- 经过代码推断,若设置了 spark.testing.memory 则以该配置的值做为 systemMaxMemory,不然使用 JVM 最大内存做为 systemMaxMemory。
- spark.testing.memory 仅用于测试,通常不设置,因此这里咱们认为 systemMaxMemory 的值就是 executor 的最大可用内存
- Execution:用于缓存shuffle、join、sort和aggregation的临时数据,经过spark.shuffle.memoryFraction配置
- spark.shuffle.memoryFraction:shuffle 期间占 executor 运行时内存的百分比,用小数表示。在任什么时候候,用于 shuffle 的内存总 size 不得超过这个限制,超出部分会 spill 到磁盘。若是常常 spill,考虑调大参数值
- spark.shuffle.safetyFraction:为防止 OOM,不能把 systemMaxMemory * spark.shuffle.memoryFraction 全用了,须要有个安全百分比
- 最终用于 execution 的内存量为:executor 最大可用内存* spark.shuffle.memoryFraction*spark.shuffle.safetyFraction,默认为 executor 最大可用内存 * 0.16
- execution内存被分配给JVM里的多个task线程。
- task间的execution内存分配是动态的,若是没有其余tasks存在,Spark容许一个task占用全部可用execution内存
- storage内存分配分析过程与 Execution 一致,由上面的代码得出,用于storage 的内存量为: executor 最大可用内存 * spark.storage.memoryFraction * spark.storage.safetyFraction,默认为 executor 最大可用内存 * 0.54
- 在 storage 中,有一部份内存是给 unroll 使用的,unroll 即反序列化 block,该部分占比由 spark.storage.unrollFraction 控制,默认为0.2
- 经过代码分析,storage 和 execution 总共使用了 80% 的内存,剩余 20% 内存被系统保留了,用来存储运行中产生的对象,该类型内存不可控.
小结:缓存
- 这种内存管理方式的缺陷,即 execution 和 storage 内存表态分配,即便在一方内存不够用而另外一方内存空闲的状况下也不能共享,形成内存浪费,为解决这一问题,spark1.6 启用新的内存管理方案UnifiedMemoryManager
- staticMemoryManager- jvm 堆内存分配图以下

Spark1.6 内存管理:安全
-
- 一方空闲,一方内存不足状况下,内存不足一方能够向空闲一方借用内存
- 只有Execution Memory能够强制拿回Storage Memory在Execution Memory空闲时,借用的Execution Memory的部份内存(若是因强制取回,而Storage Memory数据丢失,从新计算便可)
- 若是Storage Memory只能等待Execution Memory主动释放占用的Storage Memory空闲时的内存。(这里不强制取回,由于若是task执行,数据丢失就会致使task 失败)