Spark共享变量

共享变量

概述

spark算子处理数据时一般都会把所需的数据传递到计算节点。每个计算节点都有数据副本,但是数据的更新并不会传递回Driver程序,就分布式结构来说,所有节点 共享变量是比较低效的,除非有特殊优化,比如 只读 spark仍然提供了两种共享变量

广播变量

常规的数据副本机制是 每个任务一个副本,但是一个节点可能会有 多个任务,这意味着 同一个数据如果有多个task,则一个节点上可能会有多个任务副本

广播变量是把一份 只读 的数据传递给每个节点,这样可以减少节点间的通信开销。

spark操作会有多个 阶段 stage 阶段的分割线就是混洗 shuffle

广播变量创建时会被序列化,所以在使用时也会再反序列化。

所以除非是spark的多个stage使用到了同个变量,或者文件的序列化格式非常重要的情况下

这种情况可以使用广播变量

广播变量可以通过一个变量v来创建,只需调用 SparkContext.broadcast(v)即可。这个广播变量是对变量v的一个包装,要访问其值,可以调用广播变量的 value 方法。代码示例如下:

val broadcast =sc.broadcast(Array(1,2,3))
boradcast.value

广播变量在使用时需要注意

如果某个变量已经创建了广播变量,那集群内任何函数都不应该继续使用该变量。

广播变量应该避免被更新。因为更新后同步到新节点时,新节点的值会和其他节点不一致

累加器

累加器只能做累加操作

创捷累加器时需要赋一个初始值v,调用 SparkContext.accumulator(v) 可以创建一个累加器。后续集群中运行的任务可以使用 add 方法 或者 += 操作符 (仅Scala和Python支持)来进行累加操作。不过,任务本身并不能读取累加器的值,只有驱动器程序可以用 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.value
res2: Int = 10

以上代码使用了Spark内建支持的Int型累加器,开发者也可以通过子类化 AccumulatorParam 来自定义累加器。累加器接口(AccumulatorParam )主要有两个方法:

  1. zero:这个方法为累加器提供一个“零值”
  2. 2.addInPlace 将收到的两个参数值进行累加。例如,假设我们需要为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还支持几种更通用的接口:

1.Accumulable,这个接口可以支持所累加的数据类型与结果类型不同(如:构建一个收集元素的list);

2.SparkContext.accumulableCollection 方法可以支持常用的Scala集合类型。

对于在action算子中更新的累加器,Spark保证每个任务对累加器的更新只会被应用一次,例如,某些任务如果重启过,则不会再次更新累加器。而如果在transformation算子中更新累加器,那么用户需要注意,一旦某个任务因为失败被重新执行,那么其对累加器的更新可能会实施多次。

累加器并不会改变Spark懒惰求值的运算模型。如果在RDD算子中更新累加器,那么其值只会在RDD做action算子计算的时候被更新一次。因此,在transformation算子(如:map)中更新累加器,其值并不能保证一定被更新。以下代码片段说明了这一特性:

val accum = sc.accumulator(0)
data.map { x => accum += x; f(x) }
// 这里,accum任然是0,因为没有action算子,所以map也不会进行实际的计算
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值