主页(http://www.kuwanit.com):Spark 动态内存分析
声明:本文由入驻搜狐号的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。
回顾
一
因为内存可以被计算和存储内存拆借,我们必须明确在这种机制下,当内存压力上升的时候,我们如何取舍?接下来会从不同维度对下面三个取舍进行分析:
所给的两种方法都会增加额外的复杂度, 这两种方式在第一次的实现中都被排除了。综上目前看来,释放掉存储内存中的计算任务在实现上比较繁琐,目前暂不考虑。
本节将对第二部分各个内存的分布以及设计原理进行详细的阐述
(2)acquireStorageMemory(blockId:BlockId,numBytes:Long, evictedBlocks: mutable.Buffer[(BlockId,BlockStatus)])方法:
3. 保障了存储空间有一个小的保留区域。
程序一直处理该task的请求,直到系统判定无法满足该请求或者已经为该请求分配到足够的内存为止。如果当前execution内存池剩余内存不足以满足此次请求时,会向storage部分请求释放出被借走的内存以满足此次请求。
在上一篇文章末尾,我们陈述了传统spark静态内存管理模式的局限性:
1.当内存压力上升时候的取舍:
维度1、释放内存的代价
(3)那些不cache数据的应用在运行时只占用一小部分可用内存,因为默认的内存配置中,storage用去了safety内存的60%。
根据申请内存的task当前使用的execution内存大小决定分配给该task多少内存,总的内存不能超过maxMemoryPerTask。但是如果execution内存池能够分配的最大内存小于numBytes并且如果把能够分配的内存分配给当前task,但是该task最终得到的execution内存还是小于minMemoryPerTask时,该task进入等待状态,等其他task申请内存时将其唤醒。如果满足,就会返回能够分配的内存数,并且更新memoryForTask,将该task使用的内存调整为分配后的值。一个Task最少需要minMemoryPerTask才能开始执行。
实现释放存储内存的策略很简单:我们只需要用目前的内存释放策略释放掉存储内存中的数据就好了。
原标题:技术专栏 | Spark 动态内存分析
(1)acquireExecutionMemory(numBytes:Long,taskAttemptId:Long, memoryMode: MemoryMode)方法:
内存分布逻辑图
结合两篇文章,我们对spark的两种内存管理模型都做了一个简单的介绍,两者的不同之处也做出了说明,希望这两篇文章对spark的使用者有一定的帮助,也欢迎大家交流。返回搜狐,查看更多
spark.memory.storageFraction(默认 0.5):在spark.memory.fraction中存储内存所占的比例,默认是0.5,如果使用的存储内存超过了这个范围,缓存的数据会被驱赶。
维度2、实现复杂度
和动态内存相关的参数如下:
C:释放存储内存数据块,动态存储空间预留:这种设计于设计B很相似,但是存储空间的那一部分区域不再是静态设置的了,而是动态分配。这样设置带来的不同是计算内存可以尽可能借走存储内存中可用的部分。
释放计算内存的代价不是很显而易见。这里没有复用数据重计算的代价,因为计算内存中的任务数据会被移到硬盘,最后再归并起来。最近的spark版本将计算的中间数据进行压缩使得序列化的代价降到了最低。
设计A被拒绝的原因是:设计A不适合那些对cache内存重度依赖的saprk任务。
同时设计C是唯一一个同时满足下列条件的:
实现释放计算内存却相对来说很复杂。这里有几个实现该方案的思路:
在前面的一篇文章中我们介绍了spark静态内存管理模式以及相关知识点:
2 User Memory : 分配Spark Memory剩余的内存,用户可以根据需要使用。默认占(Java Heap - Reserved Memory) * 0.25。
结论:最终采用的的是设计C。
发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。