广播变量和累加器的应用场景

共享变量
提供了两种有限类型的共享变量,广播变量和累加器。

  1. 我们在dirver中声明的这些局部变量或者成员变量,可以直接在transformation中使用,
  2. 但是经过transformation操作之后,是不会将最终的结果重新赋值给dirver中的对应的变量。
  3. 因为通过action,触发了transformation的操作,transformation的操作,都是通过
  4. DAGScheduler将代码打包 序列化 交由TaskScheduler传送到各个Worker节点中的Executor去执行,
  5. 在transformation中执行的这些变量,是自己节点上的变量,不是dirver上最初的变量,我们只不过是将
  6. driver上的对应的变量拷贝了一份而已。 我们需要有一些操作对应的变量,在driver和executor上面共享

广播变量
Spark的另一种共享变量是广播变量。通常情况下,当一个RDD的很多操作都需要使用driver中定义的变量时,每次操作,driver都要把变量发送给worker节点一次,如果这个变量中的数据很大的话,会产生很高的传输负载,导致执行效率降低。使用广播变量可以使程序高效地将一个很大的只读数据发送给多个worker节点,而且对每个worker节点只需要传输一次,每次操作时executor可以直接获取本地保存的数据副本,不需要多次传输。

这样理解, 一个worker中的executor,有5个task运行,假如5个task都需要这从份共享数据,就需要向5个task都传递这一份数据,那就十分浪费网络资源和内存资源了。使用了广播变量后,只需要向该worker传递一次就可以了。

创建并使用广播变量的过程如下:
在一个类型T的对象obj上使用SparkContext.brodcast(obj)方法,创建一个Broadcast[T]类型的广播变量,obj必须满足Serializable。 通过广播变量的.value()方法访问其值。 另外,广播过程可能由于变量的序列化时间过程或者序列化变量的传输过程过程而成为瓶颈,而Spark Scala中使用的默认的Java序列化方法通常是低效的,因此可以通过spark.serializer属性为不同的数据类型实现特定的序列化方法(如Kryo)来优化这一过程。
分析一下其原理,假如在执行map操作时,在某个Worker的一个Executor上有分配5个task来进行计算,在不使用广播变量的情况下,因为Driver会将我们的代码通过DAGScheduler划分会不同stage,交由taskScheduler,taskScheduler再将封装好的一个个task分发到Worker的Excutor中,也就是说,这个过程当中,我们的genderMap也会被封装到这个task中,显然这个过程的粒度是task级别的,每个task都会封装一个genderMap,在该变量数据量不大的情况下,是没有问题的,然后,当数据量很大时,同时向一个Excutor上传递5份这样相同的数据,这是很浪费网络中的带宽资源的;广播变量的使用可以避免这一问题的发生,将genderMap广播出去之后,其只需要发送给Excutor即可,它会保存在Excutor的BlockManager中,此时,Excutor下面的task就可以共享这个变量了,这显然可以带来一定性能的提升。
这里放上从网上找的一个图,就不自己画了,原理跟上面讲的是一样的:
在这里插入图片描述

累加器

Spark提供的Accumulator,主要用于多个节点对一个变量进行共享性的操作。Accumulator只提供了累加的功能。但是确给我们提供了多个task对一个变量并行操作的功能。但是task只能对Accumulator进行累加操作,不能读取它的值。只有Driver程序可以读取Accumulator的值。非常类似于在MR中的一个Counter计数器,主要用于统计各个程序片段被调用的次数,和整体进行比较,来对数据进行一个评估。
需要注意的是,累加器的执行必须需要Action触发。

猜你喜欢

转载自blog.csdn.net/weixin_43892898/article/details/88582701
今日推荐