总结一下spark中内存分配,希望能给在座各位在工作中或面试中一点帮助!转载请注明出处:Michael孟良
在Spark 1.5版本及以前,Spark采用静态内存管理模型。Spark 1.6版本推出以后,Spark采用了统一内存管理模型。
静态内存管理模型中
Spark在一个Executor中的内存分为三块,一块是execution内存,一块是storage内存,一块是other内存。
JVM On_heap 内存
1.storage内存是存储broadcast,cache,persist数据的地方。其中10%(60%10%)用于防止OOM。另外90%中的20%用于unroll,数据展开的(比如说,rdd.perist让数据序列化持久化,当要读出来的时候就需要反序列化,可以理解为解压,这就需要unroll这部分的内存空间了),其余的内存(90%80%)用于RDD缓存数据和广播变量。
2.execution内存是执行内存,文档中说join,aggregate都在这部分内存中执行,shuffle的数据也会先缓存在这.个内存中,满了再写入磁盘,能够减少IO。其实map过程也是在这个内存中执行的。
3.other内存是程序执行时预留给自己的内存,像task的执行和task执行时产生的对象。
从Spark 1.6版本推出以后,Spark采用了统一内存管理模型。Spark 2.1.0 新型 JVM Heap 分成三个部份:Reserved Memory、User Memory 和 Spark Memor。
Spark Memeory:
系统框架运行时需要使用的空间,这是从两部份构成的,分别是 Storage Memeory 和 Execution Memory。现在 Storage 和 Execution (Shuffle) 采用了 Unified 的方式共同使用了:
(Java Heap – ReservedMemory) * spark.memory.fraction
在Spark 1.6.1中,默认为(Java Heap - 300M) * 0.75
在Spark 2.2.0中,默认为(Java Heap - 300M) * 0.6
默认情况下 Storage 和 Execution 各占该空间的 50%。你可以从图中可以看出,Storgae 和 Execution 的存储空间可以往上和往下移动。
所谓 Unified 的意思是 Storgae 和 Execution 在适当时候可以借用彼此的 Memory,需要注意的是,当 Execution 空间不足而且 Storage 空间也不足的情况下,Storage 空间如果曾经使用了超过 Unified 默认的 50% 空间的话则超过部份会被强制 drop 掉一部份数据来解决 Execution 空间不足的问题 (注意:drop 后数据会不会丢失主要是看你在程序设置的 storage_level 来决定你是 Drop 到那里,可能 Drop 到磁盘上),这是因为执行(Execution) 比缓存 (Storage) 是更重要的事情。
User Memory:
写 Spark 程序中产生的临时数据或者是自己维护的一些数据结构也需要给予它一部份的存储空间,你可以这么认为,这是程序运行时用户可以主导的空间,叫用户操作空间。它占用的空间是 :
(Java Heap - Reserved Memory) x 25% (默认是25%,可以有参数供调优)
在Spark 1.6.1中,默认占(Java Heap - 300MB) * 0.25
在Spark 2.2.0中,默认占(Java Heap - 300MB) * 0.4
这样设计可以让用户操作时所需要的空间与系统框架运行时所需要的空间分离开。假设 Executor 有 4G 的大小,那么在默认情况下 User Memory 大小是:(4G - 300MB) x 25% = 949MB,也就是说一个 Stage 内部展开后 Task 的算子在运行时最大的大小不能够超过 949MB。例如工程师使用 mapPartition 等,一个 Task 内部所有所有算子使用的数据空间的大小如果大于 949MB 的话,那么就会出现 OOM。
思考题:有 100个 Executors 每个 4G 大小,现在要处理 100G 的数据,假设这 100G 分配给 100个 Executors,每个 Executor 分配 1G 的数据,这 1G 的数据远远少于 4G Executor 内存的大小,为什么还会出现 OOM 的情况呢?那是因为在你的代码中(e.g.你写的应用程序算子)超过用户空间的限制 (e.g. 949MB),而不是 RDD 本身的数据超过了限制。
Reserved Memory:
默认都是300MB,这个数字一般都是固定不变的,在系统运行的时候 Java Heap 的大小至少为 Heap Reserved Memory x 1.5. e.g. 300MB x 1.5 = 450MB 的 JVM配置。一般本地开发例如说在 Windows 系统上,建义系统至少 2G 的大小。
ExecutionMemory 和 StorageMemory 会共享usableMemory * spark.memory.fraction(默认0.75)
注意:
在Spark 1.6.1 中spark.memory.fraction默认为0.75
在Spark 2.2.0 中spark.memory.fraction默认为0.6
如果是你的计算比较复杂的情况,使用新型的内存管理 (Unified Memory Management) 会取得更好的效率,但是如果说计算的业务逻辑需要更大的缓存空间,此时使用老版本的固定内存管理 (StaticMemoryManagement) 效果会更好
原文