【Spark精讲】RDD共享变量:广播变量与累加器

在Spark中,提供了两种类型的共享变量:广播变量 (broadcast variable)与累加器 (accumulator) 

  • 广播变量:主要用于在节点间高效分发大对象。
  • 累加器:用来对信息进行聚合,主要用于累计计数等场景;

广播变量

广播变量:允许开发者将一个只读变量(Driver端)缓存到每个节点(Executor)上,而不是每个任务传递一个副本。

每个 Task 任务的闭包都会持有自由变量的副本,如果变量很大且 Task 任务很多的情况下,这必然会对网络 IO 造成压力,为了解决这个情况,Spark 提供了广播变量。

广播变量的做法很简单:就是不把副本变量分发到每个 Task 中,而是将其分发到每个 Executor,Executor 中的所有 Task 共享一个副本变量。

注意事项:

  • 1、Driver端变量在每个Executor每个Task保存一个变量副本
  • 2、Driver端广播变量在每个Executor只保存一个变量副本
scala> val arr = Array("hello","hi","good afternoon")
val arr: Array[String] = Array(hello, hi, good afternoon)

scala> val rdd1 = sc.parallelize(List((1,"zhangsan"),(2,"lisi"),(3,"wangwu")))
val rdd1: org.apache.spark.rdd.RDD[(Int, String)] = ParallelCollectionRDD[0] at parallelize at :1

scala> val hei = sc.broadcast(arr)
val hei: org.apache.spark.broadcast.Broadcast[Array[String]] = Broadcast(0)

scala> val rdd2 = rdd1.mapValues(x => {
     |       //使用时才传给worker
     |       /*println(x)
     |       println(arr.toString())
     |       arr(0) + ":" + x*/
     | 
     |       //广播变量,提前说
     |       println(hei.value.toList)
     |       hei.value(0) + ":" + x
     |     })
val rdd2: org.apache.spark.rdd.RDD[(Int, String)] = MapPartitionsRDD[1] at mapValues at :1

scala> rdd2.foreach(println)
List(hello, hi, good afternoon)
(2,hello:lisi)
List(hello, hi, good afternoon)
(3,hello:wangwu)
List(hello, hi, good afternoon)
(1,hello:zhangsan)
                                                                                
scala>     val rdd2 = rdd1.mapValues(x => {
     |       //使用时才传给worker
     |       println(x)
     |       println(arr.toString())
     |       arr(0) + ":" + x
     |     })
val rdd2: org.apache.spark.rdd.RDD[(Int, String)] = MapPartitionsRDD[2] at mapValues at :1

scala> rdd2.foreach(println)
zhangsan
[Ljava.lang.String;@7ac9ee7
(1,hello:zhangsan)
lisi
[Ljava.lang.String;@5dcdd8ae
(2,hello:lisi)
wangwu
[Ljava.lang.String;@5dcdd8ae
(3,hello:wangwu)

累加器

原理:将每个副本变量的最终值传回 Driver,由 Driver 聚合后得到最终值,并更新原始变量。

只允许add操作,常用于实现计数。

import org.apache.spark.{SparkConf, SparkContext}

object AccumulatorDemo {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[2]").setAppName("AccumulatorDemo")
    val sc = SparkContext.getOrCreate(conf)

    val accum = sc.accumulator(0,"aaa") //第一个参数:初始值  第二个参数:name

    sc.parallelize(Array(1,2,3,4)).foreach(x=>{accum+=x;accum})
    println(accum.value)

    //拓展:glom  打印分区
    val rdd1 = sc.makeRDD(List(1,2,3,4))
    rdd1.glom().collect().foreach(x=>println(x.toList))
  }
}
/*输出:
10
List(1, 2)
List(3, 4)
*/

你可能感兴趣的:(大数据,Spark精讲,Spark,spark,大数据)