Spark2.1.0——SparkContext初始化之Spark环境的创建

阅读指导:在《Spark2.1.0——SparkContext概述》一文中,曾经简单介绍了SparkEnv。本节内容将详细介绍SparkEnv的创建过程。

         在Spark中,凡是需要执行任务的地方就需要SparkEnv。在生产环境中,SparkEnv往往运行于不同节点的Executor中。但是由于local模式在本地执行的需要,因此在Driver本地的Executor也需要SparkEnv。SparkContext中创建SparkEnv的实现见代码清单1。

代码清单1  创建SparkEnv

    private[spark] val listenerBus = new LiveListenerBus(this)
    _jobProgressListener = new JobProgressListener(_conf)
    listenerBus.addListener(jobProgressListener)

    _env = createSparkEnv(_conf, isLocal, listenerBus)
    SparkEnv.set(_env)

因为SparkEnv内的很多组件都将向LiveListenerBus的事件队列中投递事件,所以在代码清单1中首先创建LiveListenerBus和JobProgressListener,然后将JobProgressListener添加到LiveListenerBus的监听器列表中,最后将LiveListenerBus通过SparkEnv的构造器传递给SparkEnv以及SparkEnv内部的组件。JobProgressListener继承自SparkListener,LiveListenerBus和SparkListener的详细内容已在《Spark2.1.0之源码分析——事件总线》及其系列文章中介绍,此处不再赘述。

         createDriverEnv方法用于创建SparkEnv,根据createDriverEnv这个方法名,我们知道此方法将为Driver实例创建SparkEnv。调用createSparkEnv方法创建完SparkEnv后,SparkEnv实例的引用将通过SparkEnv的set方法设置到SparkEnv伴生对象[1]的env属性中,类似于设置为Java类的静态属性,这将便于在任何需要SparkEnv的地方,通过伴生对象的get方法获取SparkEnv。

         createSparkEnv方法创建SparkEnv的代码如下:

  private[spark] def createSparkEnv(
      conf: SparkConf,
      isLocal: Boolean,
      listenerBus: LiveListenerBus): SparkEnv = {
    SparkEnv.createDriverEnv(conf, isLocal, listenerBus, SparkContext.numDriverCores(master))
  }

可以看到实际调用了SparkEnv的createDriverEnv方法来创建SparkEnv。SparkEnv的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("spark.driver.port"), "spark.driver.port is not set on the driver!")
    val bindAddress = conf.get(DRIVER_BIND_ADDRESS)
    val advertiseAddress = conf.get(DRIVER_HOST_ADDRESS)
    val port = conf.get("spark.driver.port").toInt
    val ioEncryptionKey = if (conf.get(IO_ENCRYPTION_ENABLED)) {
      Some(CryptoStreamUtils.createKey(conf))
    } else {
      None
    }
    create(
      conf,
      SparkContext.DRIVER_IDENTIFIER,
      bindAddress,
      advertiseAddress,
      port,
      isLocal,
      numCores,
      ioEncryptionKey,
      listenerBus = listenerBus,
      mockOutputCommitCoordinator = mockOutputCommitCoordinator
    )
  }

createDriverEnv方法首先从SparkConf中获取4个属性。

  • bindAddress:Driver实例的host。此属性通过从SparkConf中获取DRIVER_BIND_ADDRESS指定的属性值。DRIVER_BIND_ADDRESS的定义如下:
  private[spark] val DRIVER_HOST_ADDRESS = ConfigBuilder("spark.driver.host")
    .doc("Address of driver endpoints.")
    .stringConf
    .createWithDefault(Utils.localHostName())

  private[spark] val DRIVER_BIND_ADDRESS = ConfigBuilder("spark.driver.bindAddress")
    .doc("Address where to bind network listen sockets on the driver.")
    .fallbackConf(DRIVER_HOST_ADDRESS)

根据DRIVER_BIND_ADDRESS的定义,说明按照优先级从高到低,可以通过spark.driver.bindAddress属性、spark.driver.host属性以及调用Utils的localHostName方法获得bindAddress。Utils的localHostName方法的实现请参阅附录A。

  • advertiseAddress:Driver实例对外宣称的host。可以通过spark.driver.host属性或者Utils的localHostName方法获得。
  • port:Driver实例的端口,可以通过spark.driver.port属性指定。
  • ioEncryptionKey:I/O加密的密钥。当spark.io.encryption.enabled属性为true时,调用CryptoStreamUtils的createKey方法创建密钥。

真正创建SparkEnv的实现都在create方法中,由于SparkEnv是Driver和Executor实例中都有的组件,本书将在第5章对SparkEnv作详细介绍。


[1] 什么是伴生对象?这是Scala语言的语法特性。Scala中的伴生对象可以提供类似于Java中的静态方法、静态属性等的定义,也可以支持类似于Java中的main方法。更多内容请读者阅读Scala语言相关资料。

你可能感兴趣的:(大数据,Spark,Scala,深入理解Spark)