大家好,我是一行Spark代码,我叫小小小蕉,不知道为毛,我爸爸大蕉和我妈妈大大蕉把我生的又瘦又长。长这样。
valsssjiao =newSparkContext(newSparkConf().setAppName("sssjiao").setMaster("yarn-cluster")).parallelize(Array(""));
我真的,不知道怎么说,好长好长啊。。总有小伙伴对着我说:
问君何不乘风起 扶摇直上九万里。
说出来不怕吓着你,其实我一个字都看不懂。
作为一行普通的代码,我也开始思考码生的三大问题,我是谁,我从哪里来,要到哪里去。
我从我从哪里来,开始讲我的故事吧。
我从哪里来?
这有什么好说的,出自我爸爸大大蕉之手,就酱。
本文终。
当当当,你以为就这样结束了吗?不可能的。我长得这么细这么长,其实我是由三个部分组成的。分别是SparkConf,SparkContext,RDD[String],从代码层面来说,就是定义了一个SparkConf的配置,来生成一个SparkContext上下文,然后用这个SparkContext来对数组进行序列化,我就被产生出来啦。
但是我今天不仅仅是想介绍这么浅层的来源,毕竟爸比妈咪生得我那么辛苦是吧?
(要开始Spark on yarn的深度剖析了)
大大蕉:yarn兄,我要生一个儿子,oh不我要产生一个Spark任务了,能帮忙拨 点行政资源不?
yarn :啥玩意,你想干啥?要尊贵的cluster模式还是平民的client模式?
大大蕉:这两个有啥差别?我头胎。
yarn :client就你用你自己粗糙的Driver,cluster模式就我给你分配一个高配置又漂亮的Driver。
大大蕉:那行,给我来个尊贵的cluster吧。
yarn :等着。
yarn :歪,ResourceManager吗(管资源的,下面简称RM)?你那边不是在管资源吗?咱这有货吗?赶紧给我空运一个高配的机器,嗯对,用来跑Driver和ApplicationMaster的,嗯对对对,我们这边有人快生了。对,急急急,这辈子就这要一次最急。
RM :知道了(一脸嫌弃懒洋洋)。
过了0.00001ms,对于CPU来说过了好久了
RM :NodeManage(每台机器的管家,下面简称NM),歪,根据记录你那里的配置恰好够用,你那里的Container1容器我征用了,就这样。
NM :我R。。。
RM :yarn老哥,给你那个名字为container-1的容器吧,他的地址和配置信息(CPU,内存)在这,你收好了。
yarn的最小分配单位为Container
yarn :好的,非常感谢,后面有事情还麻烦你。
yarn :大大蕉吗?Container拿到了,就是Container1,自己去看看怎么生吧。
大大蕉:好的。掰。
大大蕉:(自言自语)根据说明书,先启动一个ApplicationMaster,名字叫做sssjiao,用来管理这个Job和Container。再先启动一个Driver,来管理DAGScheduler(有向无环图管理)和TaskScheduler(任务调度管理),BlockManagerMaster(数据块管理的Master)。咦,那我去哪跑任务呢?还差一些Worker工作站啊。
Spark将一个大的任务拆成一个有向无环图,来表示依赖关系。
大大蕉:歪。yarn吗?嗯是我。我这好像还差点东西啊。。我还需要一些Container来做我的Worker啊,不然我儿子生完往哪放啊?
yarn :知道了知道了,不会一次说完吗?真讨厌。
大大蕉:我。。。我™也不知道需要这个啊。
yarn :歪。RM吗?嗯又是我。我需要一批Container。嗯对高配那种。对,急急急,这辈子就这一次最急。
RM :知道了。(不耐烦)
RM :NM-A,NM-B,NM-C,NM-D,你们几个的资源我都征用了。
NM界一脸懵逼,都感觉自己被抢劫了。。
RM :歪,yarn老哥吗?资源都ok了。ContainerA,ContainerB,ContainerC,ContainerD。
yarn :好嘞。
yarn :大大蕉。资源拿到了,信息我装在信封里了,你拿好吧。
大大蕉:嗯,我还想问一下,后面的(电话那头传来嘟嘟嘟挂断的声音)。步、骤、要、怎、么、走。算了还是自己看说明书吧。
首先在Container里面启动一个或者多个Executor,然后启动一些jvm和BlockManager。好了现在Driver、Master和Worker都有了,完事具备,只欠东西南北风了。
到这里,SparkContext算是初始化完了。
大大蕉抓着头发,一脸茫然地看着面前这堆玩意,要怎么玩。。。
诶,再看看说明书吧,看看有没有说怎么玩。(大蕉自言自语道)
突然空气中响起了旁白:切分、分配、切分、分配。
对!这个job可以先用DAGScheduler进行stage切分。
切分完然后用TaskScheduler进行任务调度分配。所以一个Job就被切分成很多个stage,封装成很多个TaskSet,然后每次Executor来请求任务的时候,就给他们分配一个,所有的Executor执行完成后又向TaskScheduler报告进度。
Task失败了?报告TaskScheduler。从头开始重新跑。
Task太慢了?TaskSchduler找多一个Executor并行跑,谁先跑完就用谁(好残忍)
Stage挂了?TaskScheduler报告DAGScheduler重新进行Stage拆分,看看是从当前开始重跑还是要用从父stage重跑。
好了到现在,小小小蕉我,还没有被产生出来。。
然后SparkContext就我的前辈Array("")进行序列化,然后根据key,也就是每个字符串进行分区,分区完之后把分区信息和对应的Executor保存起来。然后呢根据分区信息把数据发送到Executor那边去。所以我的本体RDD是在Driver的,但是我被分成很多份很小份很小份放在Exector里面的。
我是谁?
我是一个RDD。全名RDD(Reilient Distributed DataSets)弹性分布式数据集。RDD的具体描述在这里边。
我要到哪里去?
我后面的任务就是进行具体程序的执行,一个job一个job,一个stage一个stage。
这里再深入,就是从编译完的.class文件,用JVM的ClassLoader类加载器,加载完变成一个真正的类,然后再又JVM编译成机器码,在堆里开辟一点内存初始化一个String对象,在栈里开辟一点内存初始化一个指针。
然而跑完之后呢,我又将何去何从呢?
然后10M以下的就直接放在结果返回给TaskScheduler啦。
如果在10M以上的,就放到某个BlockManage,只返回BlockId了。
通知TaskScheduler说跑完啦。
然后TaskScheduler就通知DAGScheduler说跑完啦。
然后DAGScheduler就通知SparkContext说跑完啦。
然后SparkContext就通知Driver跑完啦。
然后SparkContext就准备要stop了。
大大蕉 :歪,yarn吗?我儿子生完了,资源都还给你把。
yarn :好。
yarn :歪。RM吗?刚刚申请的资源用完了,你把它们标记为可用把。
虚拟机 :这行又瘦又长的叫sssjiao的代码是谁啊。。好像被人丢在这了,诶当垃圾回收了吧,然后就给小小小蕉脸上盖上了一个待回收的印子♻️。
过了不久,小小小蕉就被GC(Garbage Collection)回收了,但是它脸上洋溢着笑容,它,是快乐的。
这就是小小小蕉快快乐乐的一生。
附上之前的好几篇Spark文章哈。
如果觉得还不错呢,就帮忙点赞评论分享一下啦,是对我最大的支持,感谢各位读者小伙伴,哇咔咔(づ ̄3 ̄)づ╭❤~。
微信公众号:一名叫大蕉的程序员