【Spark】SparkCore入门解析(四)

【Spark】SparkCore入门解析(四)_第1张图片【Spark】SparkCore入门解析(四)_第2张图片

(图片来源于网络,侵删)


一、Spark累加器和广播变量

【1】累加器

累加器是在Spark计算操作中变量值累加起来,可以被用来实现计数器、或者求和操作。Spark原生地只支持数字类型的累加器,用户可以继承累加器类来自定义累加器逻辑。如果创建累加器时指定了名字,可就以在SparkUI界面看到。这有利于理解每个执行阶段的进程。总的来说,累加器在Driver端定义赋初始值,累加器只能在 Driver 端读取,在 Driver/Excutor 端更新

我们大致看下图大致了解一下累加器:
【Spark】SparkCore入门解析(四)_第3张图片

【2】广播变量

广播变量是将变量复制到每一台机器上而不是普通变量那样复制到每个task上,从下图可以看出变量先是从远程的driver上复制到一台机器上,然后这台机器的task就从这台机器上获取变量,不需要再从远程节点上获取,减少了IO,加快了速率。广播变量只能读取,并不能修改。常用的是大表与小表的join中通过广播变量小表来实现以brodcast join取代reduce join

我们大致看下图大致了解一下广播变量:
【Spark】SparkCore入门解析(四)_第4张图片

使用广播变量的注意事项:

1)能不能将一个 RDD 使用广播变量广播出去?不能,因为RDD是不存储数据的。可以将RDD的结果广播出去

2)广播变量只能在 Driver 端定义,不能在 Executor 端定义

3)在 Driver 端可以修改广播变量的值,在 Executor 端无法修改广播变量的值

4)广播变量允许程序员将一个只读的变量缓存在每台机器上,而不用在任务之间传递变量

5)广播变量可被用于有效地给每个节点一个大输入数据集的副本

6)Spark尝试使用高效地广播算法来分发变量,进而减少通信的开销


二、依赖

何为依赖?

由于RDD是粗粒度的操作数据集,每个Transformation操作都会生成一个新的RDD,所以RDD之间就会形成类似流水线的前后依赖关系;RDD和它依赖的父RDD(s)的关系有两种不同的类型,即窄依赖(narrow dependency)和宽依赖(wide dependency)。如图所示显示了RDD之间的依赖关系
【Spark】SparkCore入门解析(四)_第5张图片

窄依赖:是指父RDD的每个Partition都只被子RDD的一个Partition使用 ,即父类RDD的一个Partition与子类RDD的一个Partition形成一对一的关系。例如map、filter、union等操作都会产生窄依赖

宽依赖:是指父RDD的Partition会被子RDD的多个Partition所使用,即父类RDD的一个Partition与子类RDD的Partition形成一对多的关系。例如 groupByKey、reduceByKey、sortByKey等操作会产生宽依赖,会产生shuffle

注意:join操作有两种情况:如果两个RDD在进行join操作时,一个RDD的partition仅仅和另一个RDD中已知个数的Partition进行join,那么这种类型的join操作就是窄依赖,例如图1中左半部分的join操作(join with inputsco-partitioned);其它情况的join操作就是宽依赖,例如图1中右半部分的join操作(join with inputsnot co-partitioned),由于是需要父RDD的所有partition进行join的转换,这就涉及到了shuffle,因此这种类型的join操作也是宽依赖

总结

在这里我们是从父RDD的partition被使用的个数来定义窄依赖和宽依赖,因此可以用一句话概括下:如果父RDD的一个Partition被子RDD的一个Partition所使用就是窄依赖,否则的话就是宽依赖。因为是确定的partition数量的依赖关系,所以RDD之间的依赖关系就是窄依赖;由此我们可以得出一个推论:即窄依赖不仅包含一对一的窄依赖,还包含一对固定个数的窄依赖。

一对固定个数的窄依赖的理解:即子RDD的partition对父RDD依赖的Partition的数量不会随着RDD数据规模的改变而改变;换句话说,无论是有100T的数据量还是1P的数据量,在窄依赖中,子RDD所依赖的父RDD的partition的个数是确定的,而宽依赖是shuffle级别的,数据量越大,那么子RDD所依赖的父RDD的个数就越多,从而子RDD所依赖的父RDD的partition的个数也会变得越来越多。


三、Spark内部通信机制

一直以来,基于Akka实现的RPC通信框架是Spark引以为豪的主要特性,也是与Hadoop等分布式计算框架对比过程中一大亮点,但是时代和技术都在演化,从Spark 1.3.1版本开始,为了解决大数据块(如shuffle)的传输问题,Spark引入了Netty通信框架,到了1.6.0版本,Netty完全取代了Akka,承担Spark内部所有的RPC通信以及数据流传输

那么Akka又是什么东西?从Akka出现背景来说,它是基于Actor的RPC通信系统,它的核心概念也是Message,它是基于协程的,性能不容置疑;基于scala的偏函数,易用性也没有话说,但是它毕竟只是RPC通信,无法适用大的package/stream的数据传输,这也是Spark早期引入Netty的原因

那么Netty为什么可以取代Akka?首先不容置疑的是Akka可以做到的,Netty也可以做到,但是Netty可以做到,Akka却无法做到,原因是啥?在软件栈中,Akka相比Netty要Higher一点,它专门针对RPC做了很多事情,而Netty相比更加基础一点,可以为不同的应用层通信协议(RPC,FTP,HTTP等)提供支持,在早期的Akka版本,底层的NIO通信就是用的Netty;其次一个优雅的工程师是不会允许一个系统中容纳两套通信框架,恶心!最后,虽然Netty没有Akka协程级的性能优势,但是Netty内部高效的Reactor线程模型,无锁化的串行设计,高效的序列化,零拷贝,内存池等特性也保证了Netty不会存在性能问题

那么Spark是怎么用Netty来取代Akka呢?一句话,利用偏函数的特性,基于Netty“仿造”出一个简约版本的Actor模型!!


都看到这里了,点赞评论一下吧!!!

点击查看

【Spark】SparkCore入门解析(五)

你可能感兴趣的:(Spark)