Spark两种内存管理
Spark动态内存管理
Spark 1.6 后改为动态内存管理(如果想启用静态内存管理,方法下面会介绍),启动动态主要体现在 存储内存和执行内存的动态。
动态内存管理内存中分为两大块和预留内存
- 用于用户数据结构和spark 元数据 的内存,默认占用整个内存的0.4
- 用于执行task 和 数据存储的内存 (M),默认占用整个内存的0.6(我这边是基于2.4,2.2版本是0.75)
- 300M 为预留内存
这个比例可以进行调整,大多数情况下不需要调整这个比例,这个比例适用于大多数情况。
spark.memory.fraction expresses 可以调整这个比例。
内存M
内存 M 分两大块,
* app 执行内存
* app 存储内存
执行内存和存储内存是可以动态借用
执行内存
也就是 shuffles joins sorts aggregations
Execution memory refers to that used for computation in shuffles, joins, sorts and aggregations
存储内存
存储内存也就是 cache(cache persist) 和 内存广播的数据(broadcast)
storage memory refers to that used for caching and propagating internal data across the cluster
在Spark中 执行内存和存储内存是在同一部分内存中。当执行内存没有用到,存储内存可以使用整个内存M,反之同理。在特殊情况下,执行内存可能会霸占存储内存,条件是 存储内存使用的空间比例大于 一个阈值 R。也就是 R区域的存储永远不会被霸占。由于现实的复杂性,存储内存不会去霸占执行内存。(霸占是我翻译后的词,翻译里面是 evict 驱赶)
这样设计的好处是:
- 当没有使用存储内存,存储内存可以使用整个M,避免不必要的磁盘溢出
- 确实使用缓存的应用程序可以保留最小的存储空间R,以免其数据块被霸占。最后,这种方法可为各种工作负载提供合理的即用性能,而无需用户了解如何在内部划分内存。
spark.memory.storageFraction 可以调整R 在M中占用的比例,默认 0.5
Spark静态内存管理
首先启用静态内存管理的方式是spark.memory.useLegacyMode true
spark.shuffle.memoryFraction
在洗牌期间用于 shuffles 过程中的aggregation and cogroups 。在任何给定时间,用于随机播放的所有内存映射的总体大小都受到此限制的限制,超出此限制,内容将开始溢出到磁盘。如果经常发生泄漏,请考虑以spark.storage.memoryFraction为代价增加此值。
我理解成 1.6后的 执行内存中一小块
spark.storage.memoryFraction
用于Spark的内存缓存的Java堆。它不应大于JVM中对象的 Old generation ,默认情况下,该对象的堆大小为0.6,但是如果您配置自己的旧代大小,则可以增加它。
也就是 存储内存
spark.storage.unrollFraction
是用于 block 序列化和反序列化的内存
Fraction of spark.storage.memoryFraction to use for unrolling blocks in memory. This is dynamically allocated by dropping existing blocks when there is not enough free storage space to unroll the new block in its entirety.
剩余的Task 执行内存
执行过程中不仅仅包含Shuffle 还有其他的计算占用内存。
本文参考
http://spark.apache.org/docs/latest/tuning.html#memory-management-overview