Spark Boradcast原理

来源:互联网 发布:淘宝foreo旗舰店真假 编辑:程序博客网 时间:2024/05/16 01:06

  • Broadcast简介
  • TorrentBroadcast
    • Driver端
    • Executor端

Broadcast简介

Spark提供的广播变量可以解决闭包函数引用外部大变量引起的性能问题。Spark使用高效的广播算法分发广播变量,以降低通信成本。广播变量会以只读形式缓存在每个机器的本地,可以使用它们以高效的方式为每个节点提供大型输入数据集的副本

广播变量的一个最重要的特点就是,在同一个执行器上的所有任务都可以共享此Broadcast,而不是每个任务使用一个变量副本。

广播变量是从一个不可变变量val v,通过调用SparkContext.broadcast(v)方法创建得到。广播变量是变量v的一个包装器,其值可以通过调用value方法得到。

scala> val broadcastVar = sc.broadcast(Array(1,2,3,4))broadcastVar: org.apache.spark.broadcast.Broadcast[Array[Int]] = Broadcast(2)scala> broadcastVar.valueres9: Array[Int] = Array(1, 2, 3, 4)

Spark Action操作的执行会经过几个Stage,而这些阶段会由分布式的Shuffle操作分隔开。Spark在每个阶段会自动广播任务需要的共同数据,以这种方式广播的数据将会以序列化的方式缓存,并在运行每个任务之前进行反序列化。这意味着,显式创建广播变量只有在跨多个阶段的任务需要相同数据时,或者以反序列化格式缓存数据时才有用。

创建广播变量后,应该在运行在集群的所有函数中使用广播变量broadcastVar而不是原始变量v,这样v就不会多次发送到节点。此外,为了保证所有节点都拥有相同的广播变量,变量v在被广播后不应该再被修改,所以应该声明为val类型。

TorrentBroadcast

Broadcast的传统实现是HTTPBroadcast,顾名思义是将Driver作为一个data server,所有的Executor都通过http协议从Driver那里拉取数据,而HttpBroadcast 最大的问题就是 driver 所在的节点可能会出现网络拥堵

为了解决HTTPBroadcast的网路拥堵问题,Spark又重新设计了一种Broadcast,称为TorrentBroadcast。类似于常见的BitTorrent技术,基本思想是将data切分为一组blocks存储于Driver的BlockManager中。假设现在有一些Executors获取到了一些blocks,那么这些Executors就可以成为data server。随着fetch的Executor越来越多,也就意味着更多的data server加入,那么data就很快能够传输到所有Executor中。下面将讨论TorrentBroadcast的具体细节:

Driver端

  1. Driver先把data序列化为byte array,然后再切割成blockSize大小的data blocks(Array[ByteBuffer])。
  2. 完成切割后,将每个分块数据存储到driver自己的BlockManager中,StorageLevel为MEMORY_AND_DISK_SER,当存储完毕后会向BlockManagerMaster进行汇报。

Executor端

  1. 首先从本地查询是否缓存了完整的data,如果查询到了,则立即返回;否则调用readBlocks从Driver或者其他Executor拉取 Torrent 块。
  2. 新建一组Array[BlockData](numBlocks)用于存储从远程拉取过来的Block,接着按照随机的索引顺序(假设有5个块,那么打乱之后,拉取的索引顺序可能为3-1-4-2-5)一个个的去fetch block data。
  3. 每个block data都有一个唯一id(e.g. broadcast_xx_piece_0),首先会根据这个id向BlockManager查询本地是否有数据,如果有则将数据放到数组中索引对应的位置;否则,根据id向BlockManager从远程拉取数据。
  4. BlockManager首先会向Driver查询该id对应的块在哪些locations上存在,当前Executor就会随机选择一个location进行下载,下载完成后,会报告给BlockManagerMaster。随着下载的Executor越多,那么这个location也就越多,data block服务器也就越多。
  5. 当获取到所有的BlockData之后(所有的BlockData都将存储在Array[BlockData]中),接着会对该array中的块数据进行反序列化得到原始的data。最后,会将data放到当前Executor的BlockManager中,那么以后再次获取data时,就可以直接从本地得到。