Spark统一内存管理模型UnifiedMemoryManager

来源:互联网 发布:做java培训讲师怎么样 编辑:程序博客网 时间:2024/04/30 17:03

从spark1.6开始,引入了新的内存管理方式-----统一内存管理(UnifiedMemoryManager)。

在统一内存管理下,Spark一个executor中的jvm heap内存被划分成如下图:


在开始介绍图中各个部分之前,我们先明确一个概念(我还是以我熟悉spark on yarn来介绍),我们在为Executor申请内存的时候,实际是JVM 的堆(heap)内存。非堆内存(off-heap)是通过

spark.yarn.executor.memoryOverhead :值为 executorMemory * 0.1, with minimum of 384

spark.yarn.driver.memoryOverhead :值为 driverMemory * 0.1, with minimum of 384

来进行配置的。也就是说executor总内存大小为spark.executor.memory + spark.executor.memoryOverhead确定的。图中这一整块所表示的就是我们申请spark.executor.memory的大小,即JVM Heap Size。

官网对memoryOverhead的描述是用来存储虚拟机(如JVM)本身开销的(interned strings, other native overheads, etc.),简单点说就是JVM如果自身占用内存越多,你就应该把memoryOverhead这个选项给调高。

在明确了上述问题后,首先来看看Reserved Memory,这一部分的内存是我们无法使用的部分,spark内部保留内存,会存储一些spark的内部对象等内容。spark1.6默认的Reserved Memory大小是300MB。这部分大小是不允许我们使用者改变的。简单点说就是我们在为executor申请内存后,有300MB是我们无法使用的。并且如果我们申请的executor的大小小于1.5 * Reserved Memory 即 < 450MB,spark会报错:

val minSystemMemory = reservedMemory * 1.5  if (systemMemory < minSystemMemory) {    throw new IllegalArgumentException(s"System memory $systemMemory must " +      s"be at least $minSystemMemory. Please use a larger heap size.")  }  

接下来我们看看User Memory,这个部分我们简单一点看,就是用户可以在程序中,开的对象存储等一系列非spark管理的内存开销都占用这一部分内存。

最后一块就是重头了,Spark Memory,该部分大小为 (JVM Heap Size - Reserved Memory) * spark.memory.fraction,其中的spark.memory.fraction可以是我们配置的(默认0.75),

而上面的User Memory的大小则为 (JVM Heap Size - Reserved Memory) * (1-spark.memory.fraction)。

可以看到,如果spark.memory.fraction配小了,我们的spark task在执行时产生数据时,包括我们在做cache时就很可能出现经常因为这部分内存不足的情况而产生spill到disk的情况,影响效率。这里官方推荐我们就用默认配置就好,不建议我们私自去改。

Spark Memory这一块有被分成了两个部分,Execution Memory 和 Storage Memory,这通过spark.memory.storageFraction来配置两块各占的大小(默认0.5,一边一半)。

Storage Memory主要用来存储我们cache的数据和临时空间序列化时unroll的数据,以及broadcast变量cache级别存储的内容。

Execution Memory则是spark Task执行时使用的内存(比如shuffle时排序就需要大量的内存)。

这里,为了提高内存利用率,spark针对Storage Memory 和 Execution Memory有如下策略:

一方空闲,一方内存不足情况下,内存不足一方可以向空闲一方借用内存。

只有Execution Memory可以强制拿回Storage Memory在Execution Memory空闲时,借用的Execution Memory的部分内存。(这里强制取回,而Storage Memory数据丢失,重新计算即可)

而如果Storage Memory只能等待Execution Memory主动释放占用的Storage Memory空闲时的内存。(这里不强制取回,因为如果task执行,数据丢失就会导致task 失败)。

(注意:各自自有的内存在不空闲的情况下是不能被对方抢占的)


0 0
原创粉丝点击