执行启动命令 jar 、wordcount
sparkSubmit:
yarnclient ->submitApplication-> ResourceManage
bin/java 在NodeManager 启动进程,ApplicationMaster
ApplicationMaster进程启动后,需要向ResourceManage注册ApplicationMaster
ApplicationMaster:
// userclass wordCount
//主线程main创建driver线程, 等待driver线程创建sc
//-》driver线程创建sc后 阻塞
//-》主线程申请计算所需资源,创建完成后恢复driver
//-》driver线程和主线程合二为一, driver线程 里的userClass.join()
主线程和driver线程交互执行
ApplicationMaster 向resourceManage 申请资源,返回可以运行的containers
根据container 的位置在 对应的NodeManger 用命令方式启动container,每个container 启动一个excutor
driver里的schedulerBacked 和 excutor 里的 Excutorbackend 互相通信,用于driver给excutor发送任务
启动完excutor ,注册excutor
创建计算对象,进行任务的划分和阶段划分,每一个任务由一个线程执行,这些线程在线程池里面
一般任务数是核数的2-3倍
一个行动算子 就是一个job
driver 负责excutor之间的任务调度
excutor 负责任务的执行,会存储rdd 和 广播变量
driver 和excutor 通信是通过rpc,rpc是进程间通信协议
netty 通信框架
BIO:block IO
NIO:non block IO,new IO
netty 使用了AIO,异步非阻塞IO
具体通信流程:
driver的transportClinent 发送数据给 excutor 的transportSever
放入inbox,经过终端处理,放入outbox,然后outbox内部的transportClinent
连接driver 的transportSever 返回数据,inbox和outbox底层都是链表
spark的任务调度:
一个行动算子是一个job
一个job根据shuffle 划分阶段
task 是依据stage的最后一个rdd的分区数
公平调度器,如果一个队列任务执行比例低,下次调度任务时,优先调度
本地化调度:
RDD的首选位置,计算发给哪个位置更好
RDD存储级别:process_local,
node_local,
rack_local(机架本地化),
没有级别,
any
spark shuffle:
影响shuffle的点: 1 磁盘
2 缓冲区(参数配置),读取缓冲区默认48M,当task数量比较多,可能需要调小
3 数据量(先filter 或者reduceByKey 数据量少 ,shuffle性能高)
4 写文件的方式
下游的多个task访问上游一个task产生的同一个溢写文件,可能冲突
解决方案:溢写文件存多份,
溢写文件数量和下游的task数量相等,
每个task单独访问
上述方案出现的问题:核数多了后,小文件过多
优化方案:一个cpu 核的所有task共享溢写文件,
溢写文件数量和下游的task数量相等
上述方案当机器数多了后,仍然小文件过多
解决方案:一个机器的一个核存一份溢写文件
该溢写文件分数据文件和索引文件,
其中数据文件是分区排序的
serializedShuffle
解释:一个对象序列化后,放入内存,可以经过压缩,这样方便传输,也可以存放更多的对象
1)支持重定位的序列化,为了防止内存碎片,kryo序列化支持,java序列化不支持
2)分区数不能大于16777216
3)不能有预聚合
sortshuffle:
reduceByKey 就是这种shuffle
if (has预聚合){
会有外部聚合器
会对key排序,这样数据查找速度快
只需要对map的value进行合并
map的底层是k,v 连起来的数组,可以看作c++的结构体数组
用数组的原因是key是排序好的,可以通过索引及二分查找法快速定位
扩展:环形缓冲区溢写前是对索引进行排序,数据不动,
这样只需要对内存的部分数据进行排序,就可以对所有数据进行排序
溢写条件:
数据量是32的倍数,并且数据量大于5M,此时会申请内存
当预估大小大于申请后的内存,需要进行溢写
当元素个数大于INT 的最大值,强制溢写
最终需要对这些临时溢写文件进行归并排序(如果能忽略,可以提高性能)
如果只有内存中有数据,那么只需要对内存数据排序,然后写文件
如果有溢写文件,需要merge,将内存数据和溢写文件合并,
最终合并成一个索引文件和一个排序好的数据文件
}
else{
存放分区,k,v
}
bypass sortshuffle:
忽略归并排序的shuffle
条件:1) 不能有预聚合功能 ,有预聚合的算子
reduceByKey,foldByKey,combineByKey,aggregateByKey
groupBykey没有
2)分区数量必须小于阈值,默认是200
为什么能忽略归并排序:
写分区数量个文件,然后直接按照分区顺序合并成一个文件,
同时创建这个文件的索引文件
注意溢写文件多的时候用bypass sortshuffle 才合适,因为当内存足够大时,
有可能sortshuffle 不溢写文件,工作中需要把bypass 阈值设高一点
默认200,可以设为500
spark 内存管理:
spark的结果可以把中间的计算过程通过内存传递
jvm 默认启动的时候是当前可用内存的1/64,最大是1/4
堆外内存是从操作系统申请的,不受gc控制,由程序自己控制
kafka 数据文件是0拷贝技术,索引文件是虚拟内存映射
executor 内存分3部分,分别是storage(30%),
execution(30%),
other(40%),
预留300M内存,防止内存溢出
rdd,catche 保存在存储内存
shuffle 需要使用执行内存
元数据信息保存在other
执行内存和存储内存有动态占用机制