SparkContext创建SparkEnv过程描述

1.简介:SparkContext是Spark的驱动器,SparkEnv是Spark的环境,这是创建驱动器环境的过程(其它的还有执行器环境),说的是创建驱动器环境的关键方法。

 

2.相关方法

SparkContext.scala文件

创建的开始:

//在SparkContext初始化中,源码第434行。调用createSparkEnv方法创建
//_conf:配置,isLocal:Boolean是否为本地模式,listenerBus:监听器队列
_env = createSparkEnv(_conf, isLocal, listenerBus)

createSparkEnv方法:

private[spark] def createSparkEnv(
      conf: SparkConf,
      isLocal: Boolean,
      listenerBus: LiveListenerBus): SparkEnv = {
      //调用到SparkEnv中createDriverEnv方法
      SparkEnv.createDriverEnv(conf, isLocal, listenerBus,  
                               //驱动器核心的数量
                               SparkContext.numDriverCores(master, conf))
  }

SparkEnv.scala文件

createDriverEnv方法:

private[spark] def createDriverEnv(
      conf: SparkConf,
      isLocal: Boolean,
      listenerBus: LiveListenerBus,  //监听器队列
      numCores: Int,  //驱动器核心数
      mockOutputCommitCoordinator: Option[OutputCommitCoordinator] = None): SparkEnv = {
    assert(conf.contains(DRIVER_HOST_ADDRESS),   //断言配置存在驱动器主机地址
      s"${DRIVER_HOST_ADDRESS.key} is not set on the driver!")
    assert(conf.contains(DRIVER_PORT), s"${DRIVER_PORT.key} is not set on the driver!")
    val bindAddress = conf.get(DRIVER_BIND_ADDRESS)   //驱动器绑定地址
    val advertiseAddress = conf.get(DRIVER_HOST_ADDRESS)   //驱动器主机地址
    val port = conf.get(DRIVER_PORT)   //驱动器端口
    //如果有配置,创建io加密密匙
    val ioEncryptionKey = if (conf.get(IO_ENCRYPTION_ENABLED)) {
      Some(CryptoStreamUtils.createKey(conf))
    } else {
      None
    }
    create(   //调用create方法
      conf,
      SparkContext.DRIVER_IDENTIFIER,   //驱动器证书
      bindAddress,
      advertiseAddress,
      Option(port),
      isLocal,
      numCores,
      ioEncryptionKey,
      listenerBus = listenerBus,
      mockOutputCommitCoordinator = mockOutputCommitCoordinator
    )
  }

create方法:

//方法为驱动程序或执行程序创建SparkEnv
private def create(
      conf: SparkConf,
      //证书
      executorId: String,
      //绑定地址   
      bindAddress: String,  
      //主机地址 
      advertiseAddress: String,   
      //端口
      port: Option[Int],   
      isLocal: Boolean, 
      //使用核心数  
      numUsableCores: Int,   
      //io加密密匙
      ioEncryptionKey: Option[Array[Byte]],   
      //监听器队列
      listenerBus: LiveListenerBus = null,   
      mockOutputCommitCoordinator: Option[OutputCommitCoordinator] = None): SparkEnv = {
    
    //是否为驱动器
    val isDriver = executorId == SparkContext.DRIVER_IDENTIFIER

    //驱动器监听器总线不能为空
    if (isDriver) {
      assert(listenerBus != null, 
             "Attempted to create driver SparkEnv with null listener bus!")
    }
    //认证密码文件配置,是驱动器还是执行器
    val authSecretFileConf = if (isDriver) AUTH_SECRET_FILE_DRIVER 
                             else AUTH_SECRET_FILE_EXECUTOR
    //安全管理器
    val securityManager = new SecurityManager(conf, ioEncryptionKey, authSecretFileConf)
    if (isDriver) {
      //初始化身份验证密码
      securityManager.initializeAuth()
    }

    ioEncryptionKey.foreach { _ =>
      if (!securityManager.isEncryptionEnabled()) {
        logWarning("I/O encryption enabled without RPC encryption: keys will be visible 
                    on the " +"wire.")
      }
    }
    //sparkDriver还是sparkExecutor
    val systemName = if (isDriver) driverSystemName else executorSystemName
    //远程通信环境
    val rpcEnv = RpcEnv.create(systemName, bindAddress, advertiseAddress, 
                   port.getOrElse(-1), conf,securityManager, numUsableCores, !isDriver)

    // 设置端口
    if (isDriver) {
      conf.set(DRIVER_PORT, rpcEnv.address.port)
    }

    // 创建具有给定名称的类的实例,可能使用我们的conf初始化它
    def instantiateClass[T](className: String): T = {
      val cls = Utils.classForName(className)
      
      // 寻找一个构造函数接受一个SparkConf和一个布尔值isDriver,
      // 然后一个只接受SparkConf,然后一个不带参数
      try {
        cls.getConstructor(classOf[SparkConf], java.lang.Boolean.TYPE)
          .newInstance(conf, java.lang.Boolean.valueOf(isDriver))
          .asInstanceOf[T]
      } catch {
        case _: NoSuchMethodException =>
          try {
            cls.getConstructor(classOf[SparkConf]).newInstance(conf).asInstanceOf[T]
          } catch {
            case _: NoSuchMethodException =>
              cls.getConstructor().newInstance().asInstanceOf[T]
          }
      }
    }

    // 如果未设置属性,则创建由给定SparkConf属性命名的类的实例,可能使用我们的conf初始化它
    def instantiateClassFromConf[T](propertyName: ConfigEntry[String]): T = {
      instantiateClass[T](conf.get(propertyName))
    }
    
    // 序列化器
    val serializer = instantiateClassFromConf[Serializer](SERIALIZER)
    logDebug(s"Using serializer: ${serializer.getClass}")

    //序列化管理器
    //为各种Spark组件配置序列化,压缩和加密的组件,包括自动选择用于shuffle的[[Serializer]]
    val serializerManager = new SerializerManager(serializer, conf, ioEncryptionKey)

    //关闭序列化器
    //使用Java内置序列化的Spark序列化程序
    val closureSerializer = new JavaSerializer(conf)

    def registerOrLookupEndpoint(
        name: String, endpointCreator: => RpcEndpoint):
      RpcEndpointRef = {
      if (isDriver) {
        logInfo("Registering " + name)
        //使用名称注册[[RpcEndpoint]]并返回其[[RpcEndpointRef]]
        rpcEnv.setupEndpoint(name, endpointCreator)
      } else {
        //通过名称检索位于驱动程序中的`RpcEndpointRef`
        RpcUtils.makeDriverRef(name, conf, rpcEnv)
      }
    }

    //广播管理器
    val broadcastManager = new BroadcastManager(isDriver, conf, securityManager)

    //map输出跟踪器
    //驱动程序端类,用于跟踪阶段的map输出的位置
    val mapOutputTracker = if (isDriver) {
      new MapOutputTrackerMaster(conf, broadcastManager, isLocal)
    } else {
      new MapOutputTrackerWorker(conf)
    }

    //由于MapOutputTrackerEndpoint需要MapOutputTracker本身
    //,因此必须在初始化后分配trackerEndpoint
    mapOutputTracker.trackerEndpoint=registerOrLookupEndpoint
      (MapOutputTracker.ENDPOINT_NAME,
       new MapOutputTrackerMasterEndpoint(rpcEnv,
        mapOutputTracker.asInstanceOf[MapOutputTrackerMaster], conf))

    // 让用户为Shuffle Manager指定短名称
    val shortShuffleMgrNames = Map(
   "sort" -> classOf[org.apache.spark.shuffle.sort.SortShuffleManager].getName,
   "tungsten-sort" -> classOf[org.apache.spark.shuffle.sort.SortShuffleManager].getName)

    
    val shuffleMgrName = conf.get(config.SHUFFLE_MANAGER)

    val shuffleMgrClass=shortShuffleMgrNames.getOrElse(
                         shuffleMgrName.toLowerCase(Locale.ROOT),shuffleMgrName)
    
    //拖拽管理器
    //驱动程序使用它注册shuffle,执行程序(或驱动程序中本地运行的任务)可以请求读取和写入数据。
    val shuffleManager = instantiateClass[ShuffleManager](shuffleMgrClass)

    //内存管理器
    val memoryManager: MemoryManager = UnifiedMemoryManager(conf, numUsableCores)

    //块管理端口
    val blockManagerPort = if (isDriver) {
      conf.get(DRIVER_BLOCK_MANAGER_PORT)
    } else {
      conf.get(BLOCK_MANAGER_PORT)
    }

    //外部拖拽客户端
    val externalShuffleClient = if (conf.get(config.SHUFFLE_SERVICE_ENABLED)) {
      val transConf = SparkTransportConf.fromSparkConf(conf, "shuffle", numUsableCores)
      Some(new ExternalShuffleClient(transConf,securityManager,
           securityManager.isAuthenticationEnabled(),
           conf.get(config.SHUFFLE_REGISTRATION_TIMEOUT)))
    } else {
      None
    }

    //块管理器的主人
    val blockManagerMaster = new BlockManagerMaster(registerOrLookupEndpoint(
      BlockManagerMaster.DRIVER_ENDPOINT_NAME,
      new BlockManagerMasterEndpoint(
        rpcEnv,
        isLocal,
        conf,
        listenerBus,
        if (conf.get(config.SHUFFLE_SERVICE_FETCH_RDD_ENABLED)) {
          externalShuffleClient
        } else {
          None
        })),
      conf, isDriver)

    //块传输服务
    //一种块传输服务,它使用Netty来获取一组块
    val blockTransferService =
      new NettyBlockTransferService(conf, securityManager, bindAddress, advertiseAddress,
        blockManagerPort, numUsableCores, blockManagerMaster.driverEndpoint)

    //块管理器。管理器在每个节点(驱动程序和执行程序)上运行
    //,它提供用于在本地和远程将块放置和检索到各种存储(内存,磁盘和堆外)的接口。
    // 注意:在稍后调用initialize()之前,blockManager无效
    val blockManager = new BlockManager(
      executorId,
      rpcEnv,
      blockManagerMaster,
      serializerManager,
      conf,
      memoryManager,
      mapOutputTracker,
      shuffleManager,
      blockTransferService,
      securityManager,
      externalShuffleClient)

    //测量系统
    val metricsSystem = if (isDriver) {
      //不要立即为Driver启动测量系统。
      //我们需要等待任务计划程序为我们提供应用程序ID。 然后我们可以启动测量系统。
      MetricsSystem.createMetricsSystem(MetricsSystemInstances.DRIVER,
                                        conf, securityManager)
    } else {
      // 我们需要在创建MetricsSystem之前设置执行程序ID
      //,因为度量配置文件中指定的源和接收器将希望将此执行程序的ID合并到它们报告的度量标准中。
      conf.set(EXECUTOR_ID, executorId)
      val ms = MetricsSystem.createMetricsSystem(MetricsSystemInstances.EXECUTOR, 
                                                 conf,securityManager)
      ms.start()
      ms
    }
    
    //输出提交协调员
    //决定任务是否可以将输出提交到HDFS的权限。 使用“第一个提交者胜利”政策。
    val outputCommitCoordinator = mockOutputCommitCoordinator.getOrElse {
      new OutputCommitCoordinator(conf, isDriver)
    }
    val outputCommitCoordinatorRef = registerOrLookupEndpoint("OutputCommitCoordinator",
      //此端点仅用于RPC
      new OutputCommitCoordinatorEndpoint(rpcEnv, outputCommitCoordinator))
    //由SparkEnv初始化
    outputCommitCoordinator.coordinatorRef = Some(outputCommitCoordinatorRef)

    val envInstance = new SparkEnv(
      executorId,
      rpcEnv,
      serializer,
      closureSerializer,
      serializerManager,
      mapOutputTracker,
      shuffleManager,
      broadcastManager,
      blockManager,
      securityManager,
      metricsSystem,
      memoryManager,
      outputCommitCoordinator,
      conf)

    //添加对驱动程序创建的tmp目录的引用,我们将在调用stop()时删除此tmp目录
    //,我们只需要为驱动程序执行此操作。 因为驱动程序可以作为服务运行
    //,并且如果我们在sc停止时不删除此tmp目录,那么将创建太多的tmp目录
    if (isDriver) {
      //createTempDir:在给定的父目录中创建一个临时目录。 当VM关闭时,将自动删除该目录
      //getLocalDir:获取临时目录的路径
      val sparkFilesDir = Utils.createTempDir(Utils.getLocalDir(conf), "userFiles").getAbsolutePath
      envInstance.driverTmpDir = Some(sparkFilesDir)
    }

    envInstance
  }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值