默认:Spark应用的算子函数中如果使用到Driver程序定义的变量,则该变量会进行反序列化并且拷贝每一个Task中,Task实际上对拷贝变量副本进行操作。
缺点:
1.内存式计算:拷贝多份相同外部变量,浪费计算节点内存空间。
2.效率:效率低,数据序列化,网络传输,浪费极大资源。
广播变量
: 优化 算法优化效率极高
广播变量使程序员可以在每台计算节点上保留一个只读变量,而不是将其副本与任务一起发送。
需要用到的依赖
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.4.4</version>
</dependency>
import org.apache.spark.{SparkConf, SparkContext}
import scala.collection.mutable.ListBuffer
object BroadcastVariableExample {
def main(args: Array[String]): Unit = {
val sc = new SparkContext(new SparkConf().setMaster("local[*]").setAppName("broadcast variable"))
// 用户信息的scala的集合
val userInfo = Map((1, "zs"), (2, "ls"), (3, "ww"))
// 标记成广播变量
val bc = sc.broadcast(userInfo)
val orderInfo = sc.makeRDD(List((101, "iphone11", 4999, 1), (102, "huawei p40", 5999, 2), (103, "mi10", 3999, 3)))
// 谁购买那个商品花费了多少钱
orderInfo
.groupBy(t4 => t4._4)
.map(t2 => {
val userId = t2._1
val orderList = t2._2
var sum = 0.0
var productList = ListBuffer[String]()
orderList.foreach(orderInfo => {
productList.+=(orderInfo._2)
sum += orderInfo._3
})
// 使用到Driver程序端变量
// val name = userInfo.get(userId)
// 获取广播变量的值
val name = bc.value.get(userId)
(name, productList, sum)
})
.foreach(println)
sc.stop()
}
}
累加器
累加器通常用于累加操作(求和计数之类),Spark内置一些基于数值计算的累加器,也允许用户自定义累加器,累加器结果最终返回给Driver程序。
import org.apache.spark.{SparkConf, SparkContext}
object AccumulatorExample {
def main(args: Array[String]): Unit = {
val sc = new SparkContext(new SparkConf().setMaster("local[*]").setAppName("broadcast variable"))
val rdd = sc.makeRDD(List(1, 2, 3, 4))
// 累加操作
// 声明累加器
val acc = sc.longAccumulator
rdd.foreach(n => acc.add(n))
// 获取累加器累加结果
println(acc.sum) // 10
println(acc.avg) // 2.5
println(acc.count) // 4
}
}