spark 内核笔记
执行启动命令 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 执行内存和存储内存有动态占用机制