Spark之广播变量Broadcast Variables与计数器Accumulators

一、广播变量Broadcast Variables
  根据官方文档,广播变量Broadcast Variables可以使开发者在每个节点–即Executor上缓存一个只读的变量,它相对于在每个task上复制一份这个变量具有更好的优势。因为它能减少网络和内存的开销。例如,有一个Map数据,大小为10M。这份数据在spark执行过程中需要被用到。下面是伪代码

val mapVar = new HashMap()
val rdd = sc.textFile("....")
rdd.map(x=>{
	...mapVar...
})		

  如果这个spark程序有50个Executor,1000个task。那么driver会将这个10M的Map分发给1000个task,共计10G。对于网络和内存来说,也是一个比较大的消耗。但是假如我们将它作为一个广播变量,那么driver只需要分发给50个Executor即可,即500M。相比之下用广播变量的方式能减少资源的浪费。注意:广播变量不能过大。

map ==> n task  <== executor
		||
		mapVar

1000task  10m  10G	
50executor 10m 500m

广播变量用例(join操作)

val g5 = Array(("1","doudou"),("2","qingfeng"),("3","yanjing"),("4","xiazhi"))
//最佳生产实践,这里使用collectAsMap(),后面可以很方便的取值
val g5Stu = sc.parallelize(g5).collectAsMap() 
val g5StuBroadcast = sc.broadcast(g5Stu)

val f11 = sc.parallelize(Array(("4","xiazhi"),("6","su")))

f11.mapPartitions(
  partition => {
    val g5Value = g5StuBroadcast.value //获取广播变量里面的内容
     for((key,value) <- partition if g5Value.contains(key))
     //针对每一次 for 循环的迭代, yield 会产生一个值,被循环记录下来 (内部实现上,像是一个缓冲区)
     //当循环结束后, 会返回所有 yield 的值组成的集合
     //返回集合的类型与被遍历的集合类型是一致的
      yield (key, g5Value.get(key).getOrElse(""))
  }).collect().foreach(println)

二、计数器Accumulators
  累加器是仅仅被相关操作累加的变量,因此可以在并行中被有效地支持。它可以被用来实现计数器和总和。Spark原生地只支持数字类型的累加器,编程者可以添加新类型的支持。如果创建累加器时指定了名字,可以在Spark的UI界面看到。这有利于理解每个执行阶段的进程。(对于python还不支持) 。
  累加器通过对一个初始化了的变量v调用SparkContext.accumulator(v)来创建。在集群上运行的任务可以通过add或者”+=”方法在累加器上进行累加操作。但是,它们不能读取它的值。只有驱动程序能够读取它的值,通过累加器的value方法。

用例:

scala> val accum = sc.longAccumulator("My Accumulator")
accum: org.apache.spark.util.LongAccumulator = LongAccumulator(id: 0, name: Some(My Accumulator), value: 0)

scala> sc.parallelize(Array(1, 2, 3, 4)).foreach(x => accum.add(x))
...
10/09/29 18:41:08 INFO SparkContext: Tasks finished in 0.317106 s

scala> accum.value
res2: Long = 10

查看Spark UI界面
在这里插入图片描述
可以看到上面设置的计数器的名称,总值,以及每个task上的值。

猜你喜欢

转载自blog.csdn.net/qq_34382453/article/details/85245430