什么是广播变量
1 在Driver初始化时,如果有一些大的变量需要进行网络传输,可以使用广播变量
2 广播变量允许开发者将一个 Read-Only 的变量缓存到集群中每个节点中(具体存入executor的BlockManager中), 而不是传递给每一个 Task 一个副本.
3 目的减少网络IO
为什么需要广播变量?
1 程序的初始化工作在Driver中进行,包括类的对象的实例化,以及方法局部变量的初始化
2 算子在worker端执行
3 如果算子中用到了Driver端初始化的对象或者局部变量,一定会涉及的网络传输
4 比如 driver初始化了一个集合,集合数据10M
val list = List("hello java")
算子rdd.filter(list.contains("a"))
用到了该list对象,所以driver要把list对象向所有的task传输一份,如果有1000 task,网络IO数据量为10000MB,影响spark运行效率.
/**
以下代码就会出现一个问题:
list是在driver端创建的,但是因为需要在executor端使用,所以driver会把list以task的形式发送到excutor端,也就相当于在executor需要复制一份,如果有很多个task,就会有很多给excutor端携带很多个list,如果这个list非常大的时候,就可能会造成内存溢出
*/
val conf = new SparkConf().setAppName("BroadcastTest").setMaster("local")
val sc = new SparkContext(conf)
//list是在driver端创建也相当于是本地变量
val list = List("hello java")
//算子部分是在Excecutor端执行
val lines = sc.textFile("dir/file")
val filterStr = lines.filter(list.contains(_))
filterStr.foreach(println)
算子如何使用广播变量?
task在运行的时候,想要使用广播变量中的数据,此时首先会在自己本地的Executor对应的BlockManager中,
尝试获取变量副本;如果本地没有,那么就从Driver远程拉取变量副本,并保存在本地的BlockManager中;
此后这个executor上的task,都会直接使用本地的BlockManager中的副本。
executor的BlockManager除了从driver上拉取,也可能从其他节点的BlockManager上拉取变量副本。
HttpBroadcast TorrentBroadcast(默认)
BlockManager的作用
负责管理某个Executor对应的内存和磁盘上的数据,尝试在本地BlockManager中找map
如何创建广播变量?
val conf = new SparkConf().setAppName("BroadcastTest").setMaster("local")
val sc = new SparkContext(conf)
//list是在driver端创建也相当于是本地变量
val list = List("hello java")
//封装广播变量
val broadcast = sc.broadcast(list)
//算子部分是在Excecutor端执行
val lines = sc.textFile("dir/file")
//使用广播变量进行数据处理 value可以获取广播变量的值
val filterStr = lines.filter(broadcast.value.contains(_))
filterStr.foreach(println)
广播变量的过程如下:
(1) 通过对一个类型 T 的对象调用 SparkContext.broadcast 创建出一个 Broadcast[T] 对象。 任何可序列化的类型都可以这么实现。
(2) 通过 value 属性访问该对象的值(在 Java 中为 value() 方法)。
(3) 变量只会被发到各个节点一次,应作为只读值处理(修改这个值不会影响到别的节点)。
能不能将一个RDD使用广播变量广播出去?
不能,因为RDD是不存储数据的。可以将RDD的结果广播出去。
广播变量只能在Driver端定义,不能在Executor端定义。