Spark1.6-----源码解读之SparkEnv

本文深入剖析Spark核心组件,包括消息传递系统RpcEnv、MapOutputTracker、ShuffleManager及BlockManager,阐述各组件作用与交互机制,揭示Spark内部运行原理。

我是跟着源码点进去一步一写的,所以观看时希望大家能一步一跟着源码走,不要只看博文。

在SparkContext 284行创建SparkEnv:

  // This function allows components created by SparkEnv to be mocked in unit tests:
  private[spark] def createSparkEnv(
      conf: SparkConf,
      isLocal: Boolean,
      listenerBus: LiveListenerBus): SparkEnv = {
    SparkEnv.createDriverEnv(conf, isLocal, listenerBus, SparkContext.numDriverCores(master))
  }

SparkEnv.createDriverEnv最终会调用SparkEnv 233行create:

  /**
   * Helper method to create a SparkEnv for a driver or an executor.
   */
  private def create(
      conf: SparkConf,
      executorId: String,
      hostname: String,
      port: Int,
      isDriver: Boolean,
      isLocal: Boolean,
      numUsableCores: Int,
      listenerBus: LiveListenerBus = null,
      mockOutputCommitCoordinator: Option[OutputCommitCoordinator] = None): SparkEnv = {

该方法会构造如下几个重要的成员:

    ①分布式消息系统RpcEnv

    ②mapOutputTracker

    ③ShuffleManager

    ④BlockManager

一一解答:

2,RpcEnv构建

个人认为,如果把分布式系统(HDFS, HBASE,SPARK等)比作一个人,那么RPC可以认为是人体的血液循环系统。它将系统中各个不同的组件(如Hbase中的master, Regionserver, client)联系了起来。同样,在spark中,不同组件像driver,executor,worker,master(stanalone模式)之间的通信也是基于RPC来实现的。

Spark 1.6之前,spark的RPC是基于Akaa来实现的。Akka是一个基于scala语言的异步的消息框架。Spark1.6后,spark借鉴Akka的设计自己实现了一个基于Netty的rpc框架。大概的原因是1.6之前,RPC通过Akka来实现,而大文件是基于netty来实现的,加之akka版本兼容性问题,所以1.6之后把Akka改掉了,具体jira见(https://issues.apache.org/jira/browse/SPARK-5293)。

本文主要对spark1.6之后基于netty新开发的rpc框架做一个较为深入的分析。

2.1整体架构

spark 基于netty新的rpc框架借鉴了Akka的中的设计,它是基于Actor模型,各个组件可以认为是一个个独立的实体,各个实体之间通过消息来进行通信。具体各个组件之间的关系图如下(图片来自[1]):

2.2 RpcEndpoint

表示一个个需要通信的个体(如master,worker,driver),主要根据接收的消息来进行对应的处理。一个RpcEndpoint经历的过程依次是:构建->onStart→receive→onStop。其中onStart在接收任务消息前调用,receive和receiveAndReply分别用来接收另一个RpcEndpoint(也可以是本身)send和ask过来的消息。

2.3 RpcEndpointRef

RpcEndpointRef是对远程RpcEndpoint的一个引用。当我们需要向一个具体的RpcEndpoint发送消息时,一般我们需要获取到该RpcEndpoint的引用,然后通过该应用发送消息。

2.4 RpcAddress

表示远程的RpcEndpointRef的地址,Host + Port。

2.5 RpcEnv

RpcEnv为RpcEndpoint提供处理消息的环境。RpcEnv负责RpcEndpoint整个生命周期的管理,包括:注册endpoint,endpoint之间消息的路由,以及停止endpoint。

SparkEnv 253行create创建RpcEnv:

    val rpcEnv = RpcEnv.create(actorSystemName, hostname, port, conf, securityManager,
      clientMode = !isDriver)

调用RpcEnv 53行getRpcEnvFactory:

    getRpcEnvFactory(conf).create(config)

 解读:同过RpcEnvFactory创建RpcEnv

RpcEnv 35行getRpcEnvFactory具体实现:

  private def getRpcEnvFactory(conf: SparkConf): RpcEnvFactory = {
    val rpcEnvNames = Map(
      "akka" -> "org.apache.spark.rpc.akka.AkkaRpcEnvFactory",
      "netty" -> "org.apache.spark.rpc.netty.NettyRpcEnvFactory")
    val rpcEnvName = conf.get("spark.rpc", "netty")
    val rpcEnvFactoryClassName = rpcEnvNames.getOrElse(rpcEnvName.toLowerCase, rpcEnvName)
    Utils.classForName(rpcEnvFactoryClassName).newInstance().asInstanceOf[RpcEnvFactory]
  }

解读:根据配置创建对应的rpc框架 ,默认为netty,通过反射创建RpcEnvFactory。

3, ActorySystem

SparkEnv 265行:

        // Create a ActorSystem for legacy codes
        AkkaUtils.createActorSystem(
          actorSystemName + "ActorSystem",
          hostname,
          actorSystemPort,
          conf,
          securityManager
        )._1

AkkaUtils 53行:

doCreateActorSystem(name, host, actualPort, conf, securityManager)

最终在AkkaUtiles 121行创建actorSystem:

   val actorSystem = ActorSystem(name, akkaConf)

解析 :因为不是很重要就没有解读了。

4, mapOutputTracker创建

mapoutputTracker用于跟踪map的输出状态,便于reduce获取。每个map或者reduce任务都会有唯一任务id。每个reduce任务的输入可能有多个map输出,reduce会到各个map任务的节点拉取Block这个过程叫shuffle,每个shuffle过程都有一个唯一标识shuffleId。

SparkEnv  328行创建mapOutputTracker:

    //根据isDriver创建不同的对象。
    val mapOutputTracker = if (isDriver) {
      new MapOutputTrackerMaster(conf)
    } else {
      new MapOutputTrackerWorker(conf)
    }

先看MapOutputTrackerMaster。

MapOutputTrackerMaster 273行 构造器:

private[spark] class MapOutputTrackerMaster(conf: SparkConf)
  extends MapOutputTracker(conf) {

比较重要的成员对象 MapOutputTracker 299行:mapStatuses,cachedSerializedStatuses 

//key为shuffleId,Array中的MapStatus跟踪各个map任务的输出状态,Mapstatus中维护的了map输出
//block的地址BolckMangerId,所以reduce知道从何处获得map任务的输出状态。
protected val mapStatuses = new TimeStampedHashMap[Int, Array[MapStatus]]()
//维护了序列化后map任务的输出状态。
private val cachedSerializedStatuses = new TimeStampedHashMap[Int, Array[Byte]]()

MapOutputTrackerWorker:

/**
 * MapOutputTracker for the executors, which fetches map output information from the driver's
 * MapOutputTrackerMaster.
 */
//从driver端获取对应的map output信息
private[spark] class MapOutputTrackerWorker(conf: SparkConf) extends MapOutputTracker(conf) {
  protected val mapStatuses: Map[Int, Array[MapStatus]] =
    new ConcurrentHashMap[Int, Array[MapStatus]]().asScala
}

回到SparkEnv

SparkEnv 334行构建MapOutputTrackerMasterEndpoint并获取MapOutputTrackerMasterEndpoint引用:

    // Have to assign trackerActor after initialization as MapOutputTrackerActor
    // requires the MapOutputTracker itself
    mapOutputTracker.trackerEndpoint = registerOrLookupEndpoint(MapOutputTracker.ENDPOINT_NAME,
      new MapOutputTrackerMasterEndpoint(
        rpcEnv, mapOutputTracker.asInstanceOf[MapOutputTrackerMaster], conf))

SparkEnv 317行registerOrLookupEndpoint具体实现:

    def registerOrLookupEndpoint(
        name: String, endpointCreator: => RpcEndpoint):
      RpcEndpointRef = {
      if (isDriver) {
        logInfo("Registering " + name)
        rpcEnv.setupEndpoint(name, endpointCreator)
      } else {
        RpcUtils.makeDriverRef(name, conf, rpcEnv)
      }
    }

解析:如果是Driver会创建MapOutputTrackerMasterEndpoint 然后获得MapOutputTrackerMasterEndpoint的引用RpcEndpointRef,

Executor直接获得MapOutputTrackerMasterEndpoint的引用RpcEndpointRef。

RpcEndpointRef可以理解为对象的引用。

map任务的状态是由Executor是向MapOutputTrackerMasterEndpoint发送消息来将map状态同步到MapStatus中的。registerOrLookupEndpoint获得的引用就是找到MapOutputTrackerMasterEndpoint的关键。

5, ShuffleManager

SparkEnv 341:

    val shortShuffleMgrNames = Map(
      "hash" -> "org.apache.spark.shuffle.hash.HashShuffleManager",
      "sort" -> "org.apache.spark.shuffle.sort.SortShuffleManager",
      "tungsten-sort" -> "org.apache.spark.shuffle.sort.SortShuffleManager")
    val shuffleMgrName = conf.get("spark.shuffle.manager", "sort")
    val shuffleMgrClass = shortShuffleMgrNames.getOrElse(shuffleMgrName.toLowerCase, shuffleMgrName)
    val shuffleManager = instantiateClass[ShuffleManager](shuffleMgrClass)

解读:ShuffleManager负责管理本地和远程的shuffle操作的。使用反射的方式生成的(默认)SortShuffleManager。

6  BlockManger

SparkEnv 364:

    // NB: blockManager is not valid until initialize() is called later.
    val blockManager = new BlockManager(executorId, rpcEnv, blockManagerMaster,
      serializer, conf, memoryManager, mapOutputTracker, shuffleManager,
      blockTransferService, securityManager, numUsableCores)

解读:BlockManager负责对Block管理。

总结

创建了几个很重要的成员。

用于进行消息传递的RpcEnv

用于负责跟踪map输出的mapOutputTracker

另外两个以后的博客会讲

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

WiFi大师是一款专为商家店内用户设计的WiFi连接小程序。它的出现有效解决了商家在为客户提供WiFi服务的过程中遇到的各种问题,为消费者提供了更加高效快捷的上网方式。除此之外,WiFi大师小程序还为商家提供了一些额外的功能,例如店铺优惠券发放和周边热门店铺展示等。这些功能为商家提供了更多的机会,吸引消费者进行二次消费,同时也可以帮助商家进行周边商圈的流量导入变现。总而言之,WiFi大师小程序不仅是一款能够满足消费者WiFi需求的工具,同时还是商家进行营销和推广的利器。它的出现为商家提供了更加全面和有效的服务和支持,有助于提高商家的客户留存率和商业价值。众人拾柴火焰高,如果需要快速赚钱的不想投资的,可以直接搜索 乐无忧wifi 小程序看案例,免费加入拓展员 即可赚钱只要合作之后,你推广的每个商家的客户通过你的二维码 扫码连接wifi的 你都有收益。 有市场的话。一天推个几十家没问题。因为咱们这个是给商家带来好处的。并不是促销产品的。※最后一张图是赠送的一个分享赚钱的软件。扫码下载转发有人看了文章就可以赚钱源码说明最新独立版WIFI分销大师V4.0.5小程序源码,一款专业WiFi分销小程序源码,该小程序源码具有完整的后端,可直接上线使用,是一款非常实用的分销小程序。独立可学习版,花大价钱买来的分享给大家产品亮点一键扫码连接安全便捷客户信息留存高效便捷商圈流量导入流量变现店铺品牌曝光免费营销系统特色提前预制WiFi空码便于后期代理推广三级分销安全合法收益比例自由设定支持个人/个体企业等资质运营TP框架独立开发无需任何第三方框架收益来源(1)卖系统我们所开发的系统采用的是Saas架构,意味着只需要部署一次系统,就可以无限开通子账户。每个子账户对应一个独立的系统,数据是完全独立的。也就是说,每个子账户都可以
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值