这是我参与[第四届青训营]笔记创作的第6天。
一、Shuffle概述
1、MapReduce概述
mapReduce分片在重组,MR程序就是封装了JOB对象,一起传递给Yarn。
在开源实现的MapReduce中,存在Map、Shuffle、Reduce三个阶段。
-
Map
键值对的集合接口:读取HDFS文件,每一行变成一<k,v>,每个键值对调用一次map。在单机上进行的针对一小块数据的计算过程。在一个Node节点上把不同颜色散乱在一起圆点根据颜色放在一起map不进行合并car1 car1,到reduce才合并car2hello you hello you变成<0,hello you><1,hello you> -
Shuffle :在Map基础上进行数据移动,为后续Reduce阶段做准备。
不同Node节点上颜色分完组之后,把颜色相同的放在一起。排序,框架做我们不用做分组,我们只map和reduce -
Reduce :对移动的数据进行处理(求和等),依然是在单机上处理一小份数据。
(1)为什么Shuffle对性能非常重要
- MxR次网络连接 、大量的数据移动、数据丢失风险、可能存在大量的排序操作、数据压缩、大量的数据序列化、反序列化操作
序列化:将结构化对象转换为字节流,以使进行网络传输或写入磁盘进行永久保存。反序列化:从网络或文件中读取的字节流转化为结构化对象。进程间通信是通过远程过程调用RFC实现的。如果自定义的序列化,不需要作为键值对参与排序,那么只需实现Writable接口。需要作为键值对参与排序,则需要Writable Comparable接口,额外实现一个基于键值进行对象比较 - 在大数据场景下,数据Shuffle表示不同分区数据交换的过程,不同的shuffle策略性能差异较大。目前在各个引擎中Shuffle都是优化的重点,在Spark框架中,Shuffle是支持Spark进行大规模复杂数据处理的基石。
MR<Spark演进过程
二、Shuffle算子
Spark中会产生Shuffle的算子大概可以分为四类有的也分为三类
- repartition:重改分区。
- ByKey:按Key聚合在一起。
- Join:把本身没在一起的按某种条件连在一起。
- Distinct:特殊的BYKey操作。
(1)Shuffle算子应用
Spark源码中RDD的单元测试[spark/RDDSuite.scala at master ·apache/spark ·GitHub]
Spark源码中PairRDDFunctions的单元测试(spark/PairRDDFunctionsSuite.scala at master · apache/spark · GitHub)
val text = sc.textFile("mytextfile.txt")\
val counts = text\
.flatMap(line => line.split(" "))\
.map(word => (word,1))\
.reduceByKey(_+_)\
counts.collect\
(2)Spark中对Shuffle的抽象-宽依赖、窄依赖
- 算子内部的依赖关系
创建会产生Shuffle的RDD时,RDD会创建Shuffle Dependency来描述Shuffle相关的信息。
(3)Shuffle Dependency 构造
1、Partitioner:两个接口
numberPartitions和getPartition 经典实现HashPartitioner
partitioner用来将record映射到具体的partition的方法。
2、Aggregator
在map侧合并部分record的函数
接口:
- CreateCombiner:只有一个Value的时候初始化的方法。
- mergeValue:合并一个Value到Aggregator。
- mergeCombiners:合并两个Aggregator。
3、Serializer:对象与二进制数据流相互映射。
三、Shuffle过程
(1)Shuffle实现的发展历程
- Hash Based Shuffle优化--优点:不需要排序。缺点:打开创建文件过多。解决数据大,占有资源多和打开文件次数多,占有资源多的问题。是C* R文件,其中C是申请CPU的核数。
虽然M变成了C但是没有解决问题,所有引入了Sort Based Shuffle - Sort based Shuffle--优点:打开的文件少,支持map-side combine、缺点:需要排序。堆内存储,
无Java对象内存开销,没有垃圾回收开销。比较key。 - TungstenSortShuffle--优点:更快的排序效率,更高的内存利用效率。缺点:不支持map-side combine。
(2)Hash Shuffle
1、写数据每个partition会映射到一个独立的文件
2、写数据优化
每个partition会映射到一个文件片段
(3)Sort Shuffle
1、写数据 每个Task生成一个包含所有partition数据的文件
2、读数据
每个reduce task分别获取所有map task生成的属于自己的片段
(4)Shuffle过程的触发流程
(5)Shuffle Handle的创建
- Register Shuffle
由action算子触发DAG Scheduler进行Shuffle register.Shuffle Register会根据不同的条件决定注册不同的ShuffleHandle。
(6)shuffle Handle和Shuffle Writer的对应关系
- BypassMergeSortShuffleWriter相当于Hash based Shuffle。
- UnsafeShuffleWriter相当于Tungsten-sort based Shuffle。
- SortShuffleWriter相当于Sort based Shuffle。
(7)Writer实现
1、BYpassMergeShuffleWriter
2、UnsafeShuffleWriter
3、SortShuffleWriter
(8)Reader实现-网络时序图
render实现,本地、外地(不需网络)
Spark底层传输netty,申请堆外内存,用0拷贝技术。同时作为网络框架提供网络服务,并接受reduce Task的fetch请求。
首先发起openBlocks请求获得Stream id,然后再处理Stream或者chunk请求。
1、ShuffleBlockFetchlterator
fetchRequests随机、fetchlocalBlocks本地
防止OOM:获取字数大小、获取请求大小、地址Block数量、请求Size放下Tomen、控制OOM次数次数越多,限制request请求。
(9)Read实现-External Shuffle Service
可以包装,对外提供一个对象,实现本身需要复制才能是实现的功能。
netty包装把两个数组的数藏起来,额外提供一个对象,这个对象看上去像有三个数组。
为了解决Executor为了服务数据的fetch请求导致无法退出问题,我们在每个节点上部署一个External Shuffle Service,这样产生数据的Executor在不需要继续处理任务时,可以随意退出。
(10)Shuffle优化使用的技术
1、Zero Copy 零拷贝:sendfile简化传输,减少上下文切换,减少复制+DMA gather copy
2、Netty zero Copy
- 可堆外内存,避免JVM堆内存到堆外内存的数据拷贝。
- CompositeByteBuf、Unpooled.wrappedBuffer、ByteBuf.slice,可以合并、包装、切分数组、避免发生内存拷贝。
- Netty使用FileRegion实现文件传输,FileRegion底层封装了FileChannel#transferTo()方法,可以将文件缓存区的数据直接传输到目标Channel,避免内核缓冲区之间的数据拷贝。
(11)Shuffle优化
1、使用可以map-side预聚合的算子
reduceing<key,value>其中key是偏移量指针,value是集合迭代器。
第一个用户看了第103个电影,评分2.5以键值对 <1,103:2.5>,<>叫范型
2、参数优化
3、倾斜优化
倾斜:假设hello7个而其他只有一个,就会导致一个Task非常大。Task整体运行时间取决于Task最大的。倾斜影响:作业运行时间变长,Task OOM导致作业失败。
常见的优化倾斜处理方法:提高并行度+AQE
`
Spark AQE Skew Join
AQE根据shuffle文件统计数据自动检测倾斜数据,将那些倾斜的分区打散成小的子分区,然后各自进行Join。
就像图中把四个虽然拆分成五个但Task变小了,速度变快。
(11)案例-参数优化
(12)参数调整
Q:上一部分所讲的shuffle过程存在哪些问题?
为了优化该问题很多公司做了思路相近的优化Push Shuffle
数据存储在本地磁盘,没有备份
IO 并发:大量 RPC 请求(M*R)
IO 吞吐:随机读、写放大(3X)
GC 频繁,影响 NodeManager
四、Push Shuffle
为什么需要Push Shuffle?
- Avg IO Size太小,造成了大量的随机IO,严重影响磁盘的吞吐。
- M* R次读请求造成大量的网络连接影响稳定性。
(1)Push Shuffle的实现 业界最火
(2)Magnet 实现原理
主要为边写边push的模式,在原有的Shuffle基础上,尝试push聚合数据,但并不强制完成,读取时优先读取push数据聚合的结果,对于没有Push来得及完成聚合或者聚合失败的情况,则fallback到原模式。
Magnet可靠性:
- 如果Map Task输出的bloke没有成功Push到magnet上,并且反复重试仍然失败,则reduce task直接从ess上拉取原始Block数据。
- 如果magnet上的block因为重复或者冲突等原因,没有正常完成merge的过程,则reduce task直接拉取未完成merge的block。
- 如果reduce拉取已经merge好的block失败,则会直接拉取merge前的原始block。
- 本质上,magnet中维护了两份Shuffle数据的副本。
(3)Cloud Shuffle Service思想字节
I/O集合后如果丢失,就得重头开始,所有得备份。
1、Cloud Shuffle Service写入流程
红框外是读取流程
2、Cloud Shuffle Service AQE
在聚合文件时主动将文件切分成若干块,当触发AQE时,按照已经切分好的文件块进行拆分。
3、实践案例-CSS优化
五、课后自测
1、自己构造一个会产生shuffle 的spark作业,修改shuffle相关的参数,对比一下不同参数对作业运行的影响。
2、在spark中shuffle实现的发展过程中,每一次变化都优化了之前哪些缺点,又带来了哪些问题?
3、Push Shuffle相对比Fetch Shuffle最大的挑战是什么?
六、电影推荐项目
1、按推荐算法分类:Collaborate协同、Filter过滤
- 协同过滤算法:userCF
两个用户兴趣相近,则A买过啥就给B推荐啥、itemCF根据我曾经买过东西推荐相似的、modelCF - 基于内容的推荐算法:用户内容属性和物品内容属性。
- 社会化过滤算法:基于用户的社会网络关系。
2、按模型划分:
- 最近邻模型(SVD):基于距离的协同过滤算法。
- Latnet Factor Model:基于矩阵分解的模型。
- Graph:图模型,社会网络图模型。
其中汇总就是同现矩阵
一起出现,考虑每个数字关联度。
减噪去除已经看过的电影视频等,避免重复推荐。例如用户A看过abc电影,用户B看过bc电影,
用户C看ac电影。减噪后A用户评分没用因为他都看过、B用户没看过a所以推荐C给a电影评分10、C用户没看过b则推荐B给c的评分7给用户C。