Broadcast(使用BroadcastManager管理)一般用於處理共享配置文件、常用的數據結構等;但Broadcast不適合存放太大數據,Broadcast不會內存溢出,因爲數據保存級別StoreageLevel是MEMORY_AND_DISK模式。數據量大會造成網絡I/O和單點壓力大,因此,當數據量較大時不要使用broadcast,網絡成本較大,會適得其反。
廣播變量:實際上就是Driver端的變量通過Broadcast方法傳輸到Executor端,Executor端不能修改廣播變量的值,使用廣播變量是爲了減少Executor端的數據備份,減少Executor端的內存。
如:driver端有100個變量,如果不使用廣播變量的話,從driver端發給executor端有100個備份,使用了廣播變量,就會只有一個備份,從而可以減少executor端的內存。
注意:
1).不能將RDD廣播出去,可以將RDD的結果廣播出去
2).廣播變量在Driver定義,在Exector端不可改變,在Executor端不能定義。
private def writeBlocks(value: T): Int = {
// 在Driver中存儲廣播變量的副本,以便在Driver上運行任務,不是創建廣播變量值得副本
SparkEnv.get.blockManager.putSingle(broadcastId, value, StorageLevel.MEMORY_AND_DISK,
tellMaster = false)
//序列化數據對象,並拆分成多個數據塊
val blocks =TorrentBroadcast.blockifyObject(value, blockSize, SparkEnv.get.serializer, compressionCodec)
blocks.zipWithIndex.foreach { case (block, i) =>
//存儲數據塊到BlockManager
SparkEnv.get.blockManager.putBytes(BroadcastBlockId(id, "piece" + i),block,StorageLevel.MEMORY_AND_DISK_SER,tellMaster = true)
}blocks.length}
代碼:
object BroadcastTest {
/**首次Broadcast變量在executor中反序列化,broadcast數據是從driver中拉取的,並存儲在executor的BlockManager中
* */
def main(args: Array[String]) {
val blockSize = if (args.length > 2) args(2) else "4096"
val spark: SparkSession = SparkSession
.builder()
.master("local[*]")
.appName("Broadcast Test")
.config("spark.broadcast.blockSize", blockSize)
.getOrCreate()
val sc = spark.sparkContext
val slices = if (args.length > 0) args(0).toInt else 2
val num = if (args.length > 1) args(1).toInt else 1000000
val arr1 = (0 until num).toArray
for (i <- 0 until 3) {
println(s"Iteration $i")
val startTime = System.nanoTime()
val barr1 = sc.broadcast(arr1)
val observedSizes = sc.parallelize(1 to 10, slices).map(_ => barr1.value.length)
/**不能將RDD廣播出去,可以將RDD的結果(如rdd.collect)廣播出去;
* 廣播變量在Driver定義,在Executor端不可改變,在Executor端不能定義*/
observedSizes.collect().foreach(i => println(i))
println("Iteration %d took %.0f milliseconds".format(i, (System.nanoTime - startTime) / 1E6))
}
spark.stop()
}
}