spark共享变量(广播变量Broadcast Variable,累加器Accumulators)

一般来说,当一个函数被传递给Spark操作(例如map和reduce),在一个远程集群上运行,它实际上操作的是这个函数用到的所有变量的独立拷贝。这些变量会被拷贝到每一台机器,在远程机器上对变量的所有更新都不会被传播回驱动程序。通常看来,在任务之间中,读写共享变量显然不够高效。然而,Spark还是为两种常见的使用模式,提供了两种有限的共享变量:广播变量和累加器。

广播变量 Broadcast Variables

广播变量允许程序员保留一个只读的变量,缓存在每一台机器上,而非每个任务保存一份拷贝。他们可以这样被使用,例如,以一种高效的方式给每个结点一个大的输入数据集。Spark会尝试使用一种高效的广播算法来传播广播变量,从而减少通信的代价。

广播变量是通过调用SparkContext.broadcast(v)方法从变量v创建的。广播变量是一个v的封装器,它的值可以通过调用value方法获得。如下模块展示了这个:

scala> val broadcastVar = sc.broadcast(Array(1, 2, 3))
broadcastVar: spark.Broadcast[Array[Int]] = spark.Broadcast(b5c40191-a864-4c7d-b9bf-d87e1a4e787c)
scala> broadcastVar.value
res0: Array[Int] = Array(1, 2, 3)

在广播变量被创建后,它应该在集群运行的任何函数中,代替v值被调用,从而v值不需要被再次传递到这些结点上。另外,对象v不能在广播后修改,这样可以保证所有结点的收到的都是一模一样的广播值。


累加器 Accumulators

累加器是一种只能通过关联操作进行“加”操作的变量,因此可以高效被并行支持。它们可以用来实现计数器(如MapReduce中)和求和器。Spark原生就支持Int和Double类型的累加器,开发者可以自己添加新的支持类型。

一个累加器可以通过调用SparkContext.accumulator(v)方法从一个初始值v中创建。运行在集群上的任务,可以通过使用+=来给它加值。然而,他们不能读取这个值。只有驱动程序可以使用value的方法来读取累加器的值。

如下的解释器模块,展示了如何利用累加器,将一个数组里面的所有元素相加:

scala> val accum = sc.accumulator(0, "My Accumulator")
accum: spark.Accumulator[Int] = 0
scala> sc.parallelize(Array(1, 2, 3, 4)).foreach(x => accum += x)
...
10/09/29 18:41:08 INFO SparkContext: Tasks finished in 0.317106 s
scala> accum.valueres2: Int = 10

 

代码使用了内建的Int的累加器, 程序员也可以自己创建累加器接口AccumulatorParam的子类。. AccumulatorParam接口有两个方法, zero代表提供一个零值,addInPlace代表将两个值相加。 例如假定我们有一个Vector类,代表数学里的vector, 我们可以实现代码如下:

object VectorAccumulatorParam extends AccumulatorParam[Vector] {
def zero(initialValue: Vector): Vector = {
Vector.zeros(initialValue.size)
}
def addInPlace(v1: Vector, v2: Vector): Vector = {
v1 += v2
}
}
// Then, create an Accumulator of this type:
val vecAccum = sc.accumulator(new Vector(...))(VectorAccumulatorParam)

如果使用Scala, Spark也支持更通用的Accumulable接口, 可以累加不同类型的元素, SparkContext.accumulableCollection方法累加通用的collection类型.

 


你可能感兴趣的:(spark共享变量(广播变量Broadcast Variable,累加器Accumulators))