Shared Variables(共享变量)
在 Spark 程序中,当一个传递给 Spark 操作 (例如 map 和 reduce) 的函数在远程节点上面运行时,Spark 实际上操作的是这个函数所用变量的一个独立副本。这些在Driver端声明的变量会被复制到每个Executor进程所在的执行机器上,并且这些变量在远程机器上的所有更新都不会传递回驱动程序。通常跨任务的读写变量是低效的,但是,Spark 为两种常见的使用模式提供了两种有限的共享变量: 广播变量(Broadcast Variable)和 累加器(Accumulator)!
1.广播变量 broadcast
1.1 为什么需要使用广播变量?
如果我们要在分布式计算里面分发大对象,例如:字典,集合,黑白名单等,这个都会由 Driver 端进行分发,一般来讲,如果这个变量不是广播变量,那么每个 task 就会分发一份, 这在 task 数目十分多的情况下 Driver 的带宽会成为系统的瓶颈,而且会大量消耗 task 服务器上的资源,如果将这个变量声明为广播变量,那么只是每个 executor 拥有一份,这个 executor 中启动的所有 task 会共享这个变量,节省了通信的成本和服务器的资源。
1.2 广播变量使用案例
import org.apache.spark.SparkContext
import org.apache.spark.broadcast.Broadcast
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.SparkSession
/**
* @author huleikai
* @create 2019-06-18 10:21
*/
object TestBroadcast {
def main(args: Array[String]): Unit = {
/* broadcast广播变量如果把某个变量进行了广播,
* 不表示每个task拥有一个副本,而是每一个executor中保持一个副本,
* 这个executor中的所有task公用这个变量副本
*/
val session: SparkSession = SparkSession.builder
.appName("TestBroadcast")
.master("local")
.getOrCreate()
val sc: SparkContext = session.sparkContext
val abc = 1
//将变量进行广播
val bc: Broadcast[Int] = sc.broadcast(abc)
val rdd: RDD[Int] = sc.makeRDD(1 to 10)
val result: RDD[Int] = rdd.map(_ + bc.value)
println(result.collect.mkString(" ")) //2 3 4 5 6 7 8 9 10 11
}
}
注意:
① 不能将一个 RDD 使用广播变量广播出去,因为 RDD 是不存储数据的,可以将 RDD 的结果广播出去
② 广播变量只能在 Driver 端定义,不能在 Executor 端定义
③ 在 Driver 端可以修改广播变量的值,在 Executor 端无法修改广播变量的值
④ 如果 executor 端用到了 Driver 的变量,如果不使用广播变量在 Executor 有多少 task 就有多少 Driver 端的变量副本。如果 Executor 端用到了 Driver 的变量,如果使用广播变量在每个 Executor 中都只有一份 Driver 端的变量副本
1.3 广播变量使用对比效果图