spark-内存管理及配置

核心概念


RDD 的所有转换都是惰性的

  • reservedMemory :系统自留空间
  • 堆内内存 : 通过JVM参数制定设置的内存空间
  • 堆外内存 : 非JVM参数设置的内存空间
  • Executor Memory : shuffle过程中的中间数据
  • Storage Memory : 缓存数据 ,cache , persist,broadcast生成的数据
  • unroll: 将Partition由不连续的存储空间转换为连续存储空间的过程,Spark称之为”展开”(Unroll)

统一内存管理


主要在UnifiedMemoryManager和MemoryManager 两个类中
maxHeapMemory = conf.getLong(“spark.testing.memory”, Runtime.getRuntime.maxMemory) 
reservedMemory = conf.getLong(“spark.testing.reservedMemory”, if (conf.contains(“spark.testing”)) 0 else RESERVED_SYSTEM_MEMORY_BYTES)
————————–
RESERVED_SYSTEM_MEMORY_BYTES = private val RESERVED_SYSTEM_MEMORY_BYTES = 300 * 1024 * 1024
————————–
MaxMemory = maxHeapMemory * conf.getDouble(“spark.memory.fraction”, 0.6) 
onHeapStorageMemory = MaxMemory * conf.getDouble(“spark.memory.storageFraction”, 0.5) 
onHeapExecutionMemory = MaxMemory – onHeapStorageMemory
————————–
UnrollMemory是在onHeapStorageMemory中分配的。
开启了spark.memory.offHeap.enabled=true,spark.memory.offHeap.size必须大于0 
————————–
maxOffHeapMemory = conf.getSizeAsBytes(“spark.memory.offHeap.size”, 0)
offHeapStorageMemory = (maxOffHeapMemory * conf.getDouble(“spark.memory.storageFraction”, 0.5)) 
offHeapExecutionMemory = maxOffHeapMemory – offHeapStorageMemory
maxHeapMemory = –executor-memory 或 spark.executor.memory 控制

堆内


堆外


动态内存分配

其中最重要的优化在于动态占用机制,其规则如下:
  • 设定基本的存储内存和执行内存区域(spark.storage.storageFraction 参数),该设定确定了双方各自拥有的空间的范围
  • 双方的空间都不足时,则存储到硬盘;若己方空间不足而对方空余时,可借用对方的空间;(存储空间不足是指不足以放下一个完整的 Block)
  • 执行内存的空间被对方占用后,可让对方将占用的部分转存到硬盘,然后”归还”借用的空间
  • 存储内存的空间被对方占用后,无法让对方”归还”,因为需要考虑 Shuffle 过程中的很多因素,实现起来较为复杂
动态占用机制图示
凭借统一内存管理机制,Spark 在一定程度上提高了堆内和堆外内存资源的利用率,降低了开发者维护 Spark 内存的难度,但并不意味着开发者可以高枕无忧。譬如,所以如果存储内存的空间太大或者说缓存的数据过多,反而会导致频繁的全量垃圾回收,降低任务执行时的性能,因为缓存的 RDD 数据通常都是长期驻留内存的 [5] 。所以要想充分发挥 Spark 的性能,需要开发者进一步了解存储内存和执行内存各自的管理方式和实现原理。

举个栗子


spark.executor.memory = 4096M(4G)

reservedMemory = 300M
MaxMemory = (4096 - 300)*0.6 = 2277.6M
onHeapStorageMemory = (4096 - 300)*0.6 * 0.5 = 1138.8M
onHeapExecutionMemory = (4096 - 300)*0.6 * (1 – 0.5) = 1138.8M
剩下的内存= 4096 - 300 - 1138.8 - 1138.8 = 1518.4M Spark 内部的对象实例,或者用户定义的 Spark 应用程序中的对象实例

再举个栗子


一台机器128G内存

spark on yarn 方式运行
yarn yarn.scheduler.maximum-allocation-mb和yarn.nodemanager.resource.memory-mb 设置为95G(97280MB).
spark.executor.cores 5~7 之间较为合理
yarn.nodemanager.resource.cpu-vcores 设置为30,那么合理的 spark.executor.cores =5 。 最多可以运行6个executor.这样可以运行的executor更多。

yarn.nodemanager.resource.memory-mb * (spark.executor.cores / yarn.nodemanager.resource.cpu-vcores) = 15G 。也就是一个executor可以运行的内存大小
spark.executor.memory = 15G

一般系统需要预留15G内存。那么可用的堆外内存是 128-95-15=18G。 现在6个executor ,那么可以使用的堆外最大内存是18/6 =3G。
到此,可以清晰的知道 一个executor可以使用的内存是
spark.executor.memory = 15G
Executor Memory (堆内)= (15G-300M) * 0.6 * 0.5 = 4518
Storage Memory (堆内) = (15G-300M) * 0.6 *  (1-0.5) = 4518

Executor Memory (堆外) = 3G * 0.5 = 1.5G
Storage Memory (堆外) = 3G * (1-0.5) = 1.5G

作者: inter12

在这苦短的人生中,追求点自己的简单快乐

发表评论

电子邮件地址不会被公开。 必填项已用*标注