第30课:彻底解密Spark 2.1.X中Shuffle中JVM Unified Memory内幕详情:Spark Unified Memory的运行原理和机制是什么?Spark JVM最小配置是什么

来源:互联网 发布:网络推广微商seocnm 编辑:程序博客网 时间:2024/05/18 00:00

第30课:彻底解密Spark 2.1.X中Shuffle中JVM Unified Memory内幕详情:Spark Unified Memory的运行原理和机制是什么?Spark JVM最小配置是什么?用户空间什么时候会出现OOM?Spark中的Broadcast到底是存储在什么空间的?ShuffleMapTask的使用的数据到底在什么地方?

  • Spark Unified Memory的运行原理和机制是什么? Spark Unified Memory,这是统一或者联合的意思,但是 Spark 没有用 Shared 这个字,例如 A 和 B 进行 Unified 和 A 和 B 进行 Shared 其实是两个不同的概念 。
  • Spark JVM最小配置是什么?
  • 用户空间什么时候会出现OOM?spark 2.1.x中用户空间OOM ,首先要确定user space memory是什么,举个很简单的例子,假如Executor 是100G的内存,那user space memory是什么,这个问题不是所有人能回答出来的,你的user space memory是50G?80G?20G?还是25G?为什么这件事情很重要,例如在spark中使用算子mapPartition,一般要使用中间数据和临时对象,你这个时候使用的中间数据和临时对象,就是user space里面用户操作的数据空间,那这个空间的数据大小什么时候导致OOM?
  • Spark中的Broadcast到底是存储在什么空间的?
  • ShuffleMapTask的使用的数据到底在什么地方?是存在cache空间中吗?

本文根据家林大神系列课程编写 http://weibo.com/ilovepains

左侧图是spark 1.6.x的内存管理分配图,是本节课讲解的重点;  右侧的图是spark 1.6.x之前的内存示意图,可以看上一节课(第29课http://blog.csdn.net/duan_zhihua/article/details/71244384)的内容。本节课的内容必须搞懂,不搞懂的话,很多内存的bug就不知道怎么回事。

 

1,对于spark 2.1.0新型的JVM HEAP分为三大部分:

  • Reserved Memory
  • User Memory
  • Spark Memory

2,预留内存Reserved Memory:系统运行的时候至少HEAP的大小为300M*1.5=450M。一般本地开发例如说在windows系统上,建议windows系统至少2G。 


3,User Memory :

从spark的程序讲,什么是user memory?什么时候接触到memory的空间?我们基于RDD编程,这件事情是否在使用
user memory的空间?是也不是,这个问题好像答不出来。说白了:user memory就是RD具体实现的方法中map,mapPartitions中,你会写自己的代码,怎么实现处理作用RDD的数据,举个很简单的例子,你可能使用一个数据结构,mapPartitions处理一个partition的时候有5000个record记录要处理,在这个过程中建立了一些临时数据,这些数据实际意义上讲和spark本身不太相关,作为开发者user引入的中间数据,这些数据是否缓存在spark的storage memory中呢?是还是不是以及为什么?不直接告诉大家的结果。佛祖曾经讲的经典一课:佛祖拈花一笑,从一朵花中看出一切,或者全世界。希望大家从spark这样的一个平台一个技术体系中获得人生的一切答案!

大家想一下:5000个record记录产生的中间数据放在哪里是一件很重要的事情,例如产生的中间数据是10G的大小,或者1M的大小,对系统的运行有什么影响?单机版本的JAVA,Python就是这种级别的内存,分配一个list、map,或者ARRAY,写一个循环进行处理,例如读数据库对key进行匹配,或者累加一个数据,你自己维护的数据是否会导致出现OOM。在spark中,人们对算子里面RDD数据以外的数据及数据结构却不那么重视,而在单机版本编程的时候里面我们重视的主要就是这些数据结构及数据。

你在mapPartitions算子中间使用的的数据,也就是说不是RDD数据的数据,是存储在spark memory中吗?解释一下:spark memory是spark框架使用的内存空间,相当于编程的时候涉及2个方面:1,框架方面:如tensorFlow,把特征提取也帮你干了,解决了图像、声音特征的识别;2,另一方面是用户的部分,例如用户只要调声音、图像、深度学习一些东西。

从spark的角度讲:也分spark框架的部分和用户空间的部分
spark Memory就是spark运行时候可以主导哪些空间!
user Memory就是你可以主导哪些空间:你在什么时候主导空间呢?唯一主导的时候就是map,mapPartioion ,groupByKey,aggregate
操作的时候中间会产生一些数据结构,这些数据结构就在userMemory中。而系统的空间不可侵犯的!spark在新版本空间划分非常明智,将用户空间,spark空间完全分离开!也是从安全方面的考量!
 
用户空间User Memory的计算公式 : (HEAP size - Reserverd Memory)*25% (默认情况下是25%)这是用户可以支配的空间,从编程的角度讲,必须思考一件事情,用户可以支配多少空间,否则会出现OOM。举个简单的例子,例如有4G大小,那么默认情况下User Memory大小是(4G-300M)*25%=949M,所以你在算子中,作为stage的task的角度去讲,task本身运行的时候展开的每一个RDD算子的内部,从我们4G大小的角度讲,你的mapPartiton,你的stage可能有很多算子,map等其他的一些算子,最大的使用的空间不能超过949M,我们没有说task的运行占用的空间不能超过949M,我们说的是stage内部的task的所有算子在运行的时候中间的数据不能超出949M,这完全是两码事。task的运行是被spark框架使用的,用户是无能为力的!用户只不过把自己的逻辑和数据嵌入到后来框架称之为task一个又一个RDD的算子而已,我们谈的是 数据在Rdd算子中一个stage内部一个task的运行这些算子占用多大空间,就象mapPartitions中循环遍历数据库的record,要累加数据,中间使用array,一下使用2G,对不起,就会出现OOM。如果工程师使用例如mapPartitions等一个Task内的所有算子使用的数据空间的大小大约949M的话,那么就会出现OOM。


面试题:100个Executor 每个4G大小,处理10G的大小,是否OOM?答:这个不好说。
  每个Executor的内存是4G大小,然后有100个Executor,处理的磁盘数据一共才100G,理论上分配在100个Executor,每个Executor分配1G的数据,远远小于4G的大小,为什么会出现OOM?别说100G的磁盘数据,10G的磁盘数据也会出现OOM,因为在mapPartitions算子,你
使用的算子数据而不是RDD的本身数据超过了user Memory的大小。


4,Spark Memory 是框架空间,由两部分构成:

   storage Memory :相当于spark 1.6.x之前旧版本的storage空间,旧版本的storage占了是54%的Heap空间。
   Execution Memory:相当于spark 1.6.x之前旧版本的shuffle空间,命名非常科学的,执行分成许多stage,分析的就是shufffle。代码运行的时候也是谈shuffle。从整个运行的流程来讲,涉及从上一个stage抓数据,涉及到聚合的操作。旧版本的storage占了是54%的Heap空间,shuffle在旧版本中占了的是14.4%。你认为这个数据合理吗?是数据缓存重要,还是执行重要?即是程序先跑起来重要呢?还是搞性能调优重要?当然是程序跑起来重要,shuffle肯定是最重要的!而遗憾的是 spark 1.6.之前的版本中没有体现execution最重要的位置。现在storage和shuffle其实是采用“Unified”的方式共同使用(Heap size -300M)*75%,默认情况下,storage和execution各占该空间的50%,默认情况下平分,但是这里并没有体现“unified”,从箭头的角度看一个往上,一个往下。我们马上谈往上,往下的问题。先补充一个点:storage memory新版本和旧版本有一个存储是一样的, storage中会负责Persist、Unroll及Broadcast的数据,广播是广播到这里面,大变量的广播出去是有道理的,因为这个空间还是很大的,从默认的情况讲,假设4G的空间减去300M,乘以75%,再乘以50%,算下来大约1.5G左右的空间,确实可以广播一些大变量。如果内存足够大,可以广播足够大的变量,对于性能有很大的提升,对于线程共享的,HEAP 的对象是线程共享的。而线程私有的是stack。这个和JVM联系在一块了。
也可以从另外一个角度讲:这个是execution memory,也就是task运行级别的东西,execution memory是从shuffleMapTask的角度来看的,作为task运行的,运行在线程之上,这个user memory是用户的数据,相当于是私有的,私有是从算子的角度讲。但是从整体上讲,
大家都是这种类型的,也可以认为公有的。这个和heap、stack是完全两个不同层面的东西。这个数据为什么非常重要?是因为从算子运行的角度来讲,尽可能倾向于从storage memory中拿到数据,这是所谓的内存计算,我们的Persist、Unroll及Broadcast的数据都在storage memory空间。如果说是4G的堆大小,storage memory占到1.5G左右,execution memory也是占到1.5G左右。

现在讲“unified”:
第一点,Storage和Execution在适当的时候可以借用彼此的memory。execution memory可以使用storage memory;storage memory也可以使用execution memory。相当于男生、女生谈恋爱,男生可以使用女生的资源,女生也可以使用男生的资源。
第二点,当Execution空间不足而且storage空间也不足的时候,storage 空间会被强制drop掉一部分数据来解决Execution的空间不足问
题,hopefully。举个例子,如4G的空间,两个加一起空间不到3G的样子,非要用4G的空间,怎么解决也解决不了。storage空间不足的情况下,execution空间也不足,这个时候放弃掉storage的一部分空间来满足execution的空间需求,为什么这么做?原因很简单,执行是更重要的事情!运行都运行不起来了,还管什么缓存?这里使用的是drop,没有说丢失,drop可能drop到Disk中,看persist的level级别。例如,男生、女生都有困难的情况下,优先解决女生,或者强制解决女生的困难,这里有个底线,这个底线的东西,execution向storage借空间分成2种情况:1,execution向storage能借到空间的情况:storage曾经向execution借了空间,由于缓存的时候,数据非常的多,execution又不需要那么多的空间,原先各自平分50%;storage默认占了75%的空间或者80%,如execution使用了20%的空间,那么空间不足了,execution需要将你曾经占用的空间数据强制drop掉,execution会向内存管理器发信号,那原先storage memory占据了共用空间的80%的话,那现在execution memory需要占用更多的空间,那是否是说execution memory可以将storage memory80%的数据空间都拿过来呢?假设说execution数据特别特别庞大。肯定不是的,这种情况下(storage memory曾经超过了50%的空间),execution这个时候需要更多的空间,他能做的一件事情是:execution把曾经storage memory占用的超过50%的内容挤掉,但是剩下的,storage memory还是占据50%的空间execution memory不能继续把别人(storage memory)的数据挤掉了,这个有个限度的。2,execution向storage 拿memory,memory不足50%的空间,这个时候就需要拿memory的空间了。这是execution可以强制要空间的2种情况。
       在execution有剩余空间的时候,storage memory可以向execution借空间,而如果execution没有空间,那么storage是不能借的。

最后一个重磅点:
1,execution如果已经占据了execution和storage的80%的共用空间,这个时候storage需要更多的空间,能不能向execution借空间? 把默认超过50%的剩余30%的空间拿回去呢?那storge是拿不回去的。execution是最重要的!(体现了男女不平衡,就象女生霸占了男生的空间,这个是拿不回去的)
2,无论execution 还是storage的空间,execution 空间不足的情况下,可以spill到磁盘上,但shuffle这个最影响性能的。解决了shuffle的问题,就解决了95%的spark的性能问题。所以execution 很强势,execution 可以强制使用空间,这个是有道理的,因为execution 跟贡献成正比的。execution 将storage的空间占用了,storage曾经没有占用的空间被execution 空间占用了,storage如果需要空间,execution 也不给storage!execution 是最重要的!而如果storage占用了超过50%的空间,execution 需要更多的空间,那execution 将storage空间挤掉

5,ShuffleMapTask的使用的数据到底在什么地方?

放在execution memory中,例如聚合数据过来,从500个Executor中抓数据过来,就放在execution memory中。至于说storage memory是缓存,和shuffle过来的数据是两码事,如果本地有数据,那干嘛用shuffle。

 

补充:spark RDD的运行空间说明:

(1)输入:在Spark程序运行中,数据从外部数据空间(如分布式存储:textFile读取HDFS等,parallelize方法输入Scala集合或数据)输入Spark,数据进入Spark运行时数据空间,转换为Spark中的数据块,通过BlockManager进行管理。
(2)运行:在Spark数据输入形成RDD后面可以通过变换算子(transformations算子),如filter等,对数据进行操作并将RDD转化为新的RDD,通过Action算子,触发Spark提交作业。如果数据需要复用,可以通过Cache算子,将数据缓存到内存中。
(3)输出:程序运行结束数据会输出Spark运行时的内存空间,存储到分布式存储中(如saveAsTextFile输出到HDFS),或Scala类型的数据或集合中(collect输出到Scala集合,count返回Scala int型数据)。



0 0
原创粉丝点击