Spark BroadCast 解析

 

前言

在实际使用中对于一些许多rdd需要用到的大的只读数据集变量可以使用共享变量的方式来提高性能,例如查内存表,默认情况下会每个task都保存一份,这样太浪费资源,所以一般会采用共享变量的方式来查表,代码中经常使用,但还没细致研究过,这次刚好借着阅读Spark RDD API源码的机会来深入解析一下broadcast

Broadcast代码还涉及到spark底层存储代码BlockManagerBlockId等。

 

 

简介

Broadcast变量使得编程人员在每一台机器上保存一份只读类型的变量而不需要为每一个task保存一份。在为每一个节点保存一份较大的输入数据集时这是一种很高效的手段,另外spark还尝试用高效的高效broadcast算法去减少通信开销。

 

基础类

abstract class Broadcast[T: ClassTag](val id: Long) extends Serializable with Logging {

 

该虚类有两种实现方式:

 

对应着两种网络协议类型,http协议和比特流bittorrent协议。

BroadcastFactory接口用来初始化和新建不同类型的broadcast变量,sparkContext会为不同用户产生特定的broadcast变量。

trait BroadcastFactory {

一共有下列方法:

 

该接口也有两种继承方式:

 

BroadcastManager负责具体的broadcast的初始化、删除和管理工作

private[spark] class BroadcastManager(
    val isDriver: Boolean,
    conf: SparkConf,
    securityManager: SecurityManager)
  extends Logging {

对应的方法和变量有:

 

 

bitTorrent-like broadcast

这里先简单介绍下比特流协议:

比特流Bit-torrent是一种内容分发协议,有布拉姆科恩自主开发。它采用高效的软件分发系统和P2P技术共享大体积文件(如一部电影或电视节目),并使每个用户像网络重新分配结点那样提供上传服务。一般的下载服务器为每一个发出下载请求的用户提供下载服务,而bitTorrent的工作方式与之不同。分配器或文件的持有者将文件发送给其中一名用户,再由这名用户转发给其他用户,用户之间相互转发自己所拥有的文件部分,直到每个用户的下载全部完成。这种方法可以使下载服务器同时处理多个大体积文件的下载请求,而无需占用大量带宽。

首先是TorrentBroadcastFactory

class TorrentBroadcastFactory extends BroadcastFactory {
  override def initialize(isDriver: Boolean, conf: SparkConf, securityMgr: SecurityManager) { }

  override def newBroadcast[T: ClassTag](value_ : T, isLocal: Boolean, id: Long): Broadcast[T] = {
    new TorrentBroadcast[T](value_, id)
  }

  override def stop() { }

  /**
   * Remove all persisted state associated with the torrent broadcast with the given ID.
   *
@param removeFromDriver Whether to remove state from the driver.
   *
@param blocking Whether to block until unbroadcasted
   */
  
override def unbroadcast(id: Long, removeFromDriver: Boolean, blocking: Boolean) {
    TorrentBroadcast.unpersist(id, removeFromDriver, blocking)
  }
}

 

5个功能函数:

 

注意Initializestop都是空函数,没有实际的操作。

 

TorrentBroadcast是重点:

private[spark] class TorrentBroadcast[T: ClassTag](obj: T, id: Long)
  extends Broadcast[T](id) with Logging with Serializable {

继承自Broadcast类,spark命名空间下的私有类

代码结构:

 

注意Object TorrentBroadcast中的方法。

 

下面开始详细分析这个类

该类是对org.apache.spark.broadcast.Broadcast类的一种类似比特流形式的实现,具体机制如下:

Driver将序列化后的对象切分成许多小块,将这些小块保存在driverBlockManager中。在每个executor上,每个executor首先尝试从自己的本地BlockManager上去获取这些小块,如果不存在,就会从driver或者其他的executor上去获取,一旦获取到了目标小块,该executor就会将小块保存在自己的BlockManager中,等待被其他的executor获取。

这种机制使得在driver发送多份broadcast数据时(对每一个executor而言)避免成为系统的瓶颈,如果采用前面提到的org.apache.spark.broadcast.HttpBroadcast方式的话就使得driver成为整个系统的瓶颈了。

在初始化的时候,TorrentBroadcast 对象会去读取SparkEnv.get.conf

Executor上的broadcast的对应值,值由readBroadcastBlock方法获取,通过读取存储在driver或者其他executor上的block获得,在driver上,只有当真正需要该值时,才会通过blockManager去惰性读取。

@transient private lazy val _value: T = readBroadcastBlock()

setConf

通过配置文件获取是否需要对broadcast进行压缩,并设置环境配置。

private def setConf(conf: SparkConf) {
  compressionCodec = if (conf.getBoolean("spark.broadcast.compress", true)) {
    Some(CompressionCodec.createCodec(conf))
  } else {
    None
  }
  // Note: use getSizeAsKb (not bytes) to maintain compatiblity if no units are provided
  blockSize = conf.getSizeAsKb("spark.broadcast.blockSize", "4m").toInt * 1024
}
setConf(SparkEnv.get.conf)

writeBlocks

/**
 * Divide the object into multiple blocks and put those blocks in the block manager.
 *
@param value the object to divide
 *
@return number of blocks this broadcast variable is divided into
 */
private def writeBlocks(value: T): Int = {
  // Store a copy of the broadcast variable in the driver so that tasks run on the driver
  // do not create a duplicate copy of the broadcast variable's value.
  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) =>
    SparkEnv.get.blockManager.putBytes(
      BroadcastBlockId(id,

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值