Spark源码阅读#1:SparkConf详解

1. 类作用

我们Spark的代码开头往往是这样的

val conf: SparkConf = new SparkConf().setAppName("app").setMaster("local[2]")

根据代码和官方的注释可以知道,SparkConf是Spark应用程序的配置类,通常用来设置KV结构的Spark参数。它还具有以下基础的特性。

  1. 当使用new SparkConf()时,大多数情况下会把Java参数(resource)中带有Spark.*格式的参数自动设置到应用中。但是,你通过set方法直接设置的属性优先级会高于Java参数(resource)。
  2. 你也可以通过new SparkConf(false)的方式来跳过加载系统参数的过程。
  3. 一旦一个SparkConf初始化后到了Spark运行的集群中,运行过程中用户是不可以改变SparkConf对象的。

2. 主要函数

2.1 构造方法

class SparkConf(loadDefaults: Boolean) extends Cloneable with Logging with Serializable {

  import SparkConf._

  /** Create a SparkConf that loads defaults from system properties and the classpath */
  def this() = this(true)

  private val settings = new ConcurrentHashMap[String, String]()
  //......
}

首先是import SparkConf._,它引入的伴生对象有如下方法

  1. 伴生对象中有个Map记录了Spark不推荐的配置和对应的日志信息
  2. 第二个Map记录当前版本键和历史版本Spark的备用键的关系,显然是做兼容用,它还有对应的高效查询的方法。
  3. 是否将参数传递给执行器的方法。
  4. 判断和打印弃用参数的方法。

其次是settings,它是一个线程安全的Map来作为Spark配置项的容器。

2.2 reader&loadFromSystemProperties

@transient private lazy val reader: ConfigReader = {
    val _reader = new ConfigReader(new SparkConfigProvider(settings))
    _reader.bindEnv((key: String) => Option(getenv(key)))
    _reader
  }
}

reader是个懒加载的方法,它最后返回的是一个ConfigReader对象,这个对象作用是帮助读取配置参数和参数格式的替换。读取的参数按照前缀分为三种:

  • no prefix: 无前缀,使用默认配置
    • 在创建ConfigReader对象时,传入了一个SparkConfigReader对象,这个对象封装了前面提到的Spark参数容器settings,它就作为无前缀配置项让ConfigReader读取
  • system:从系统参数中读取
  • env:从环境参数中读取
    • 创建时reader先执行了一次bindEnv

这个类构造了一个Map类型的属性bindings作为以上三种参数的容器,类里也有对应参数类型的bind方法将参数注入到bindings中,最后统一替换bindings的格式。
参数替换使用了一个正则表达式将参数替换成prefix:name的形式。

最终返回的reader将在运行时由其他类通过相应get方法获取配置参数。

private[spark] def get[T](entry: ConfigEntry[T]): T = {
    entry.readFrom(reader)
}

if (loadDefaults) {
    loadFromSystemProperties(false)
}

private[spark] def loadFromSystemProperties(silent: Boolean): SparkConf = {
  // Load any spark.* system properties
  for ((key, value) <- Utils.getSystemProperties if key.startsWith("spark.")) {
    set(key, value, silent)
  }
  this
}

其次是loadFromSystemProperties,就是开头提到的加载Java参数,类的唯一一个参数loadDefaults就是控制是否加载Java参数。
方法内部遍历spark.开头的参数然后由set方法注入到setttings中。

2.3 set方法

private[spark] def set(key: String, value: String, silent: Boolean): SparkConf = {
    if (key == null) {
      throw new NullPointerException("null key")
    }
    if (value == null) {
      throw new NullPointerException("null value for " + key)
    }
    if (!silent) {
      logDeprecationWarning(key)
    }
    settings.put(key, value)
    this
}

set方法不允许key或value为空,否则会抛出空指针异常,silent属性判断参数是否过期,最后放入settings中。返回this可以让我们链式调用set方法,即文章开头示例代码。
除此以外,常用的setMaster,setAppName以及其他的setXX方最后调用的都是上面的基础set方法。

2.4 get方法

def getOption(key: String): Option[String] = {
    Option(settings.get(key)).orElse(getDeprecatedConfig(key, settings))
}

settings获取到的值作为Option返回,如果settings没有相应的key则会通过伴生对象的方法查找是否是过期的配置项。
其他封装的get方法例如带有默认值的get,获取各种类型的get等最终调用的都是getOption

2.5 validateSettings方法

源码过长就不贴了,这个方法会校验某些特殊参数并打印warn,还会校验JVM参数和内存参数的合法性,逻辑较为简单。

3. 总结

SparkConf就是用于各种参数的获取和配置,并最后作为参数传入到SparkContext中,SparkContext是程序总入口,它接受了SparkConf定义的配置参数后开始初始化工作,然后运行程序。

你可能感兴趣的:(大数据)