zoukankan      html  css  js  c++  java
  • Spark之SparkContext源码分析

    一.简介

      SparkContext是Spark程序最主要的入口,用于与Spark集群连接。Spark集群的所有操作都通过SparkContext来进行,使用它可以在Spark集群上创建RDD、计数器以及广播变量。所有的Spark程序都必须创建一个SparkContext对象。进行流式计算时使用的StreamingContext以及进行SQL计算时使用的SQLContext也会关联一个现有的SparkContext或者隐式创建一个SparkContext对象。源码如下:

     /** * Main entry point for Spark functionality. A SparkContext represents the connection to a Spark
    * cluster, and can be used to create RDDs, accumulators and broadcast variables on that cluster. * * Only one SparkContext may be active per JVM. You must `stop()` the active SparkContext before * creating a new one. This limitation may eventually be removed; see SPARK-2243 for more details. * * @param config a Spark Config object describing the application configuration. Any settings in * this config overrides the default configs as well as system properties.
    */ class SparkContext(config: SparkConf) extends Logging { // The call site where this SparkContext was constructed. private val creationSite: CallSite = Utils.getCallSite() // If true, log warnings instead of throwing exceptions when multiple SparkContexts are active private val allowMultipleContexts: Boolean = config.getBoolean("spark.driver.allowMultipleContexts", false) // In order to prevent multiple SparkContexts from being active at the same time, mark this // context as having started construction. // NOTE: this must be placed at the beginning of the SparkContext constructor. SparkContext.markPartiallyConstructed(this, allowMultipleContexts) val startTime = System.currentTimeMillis() private[spark] val stopped: AtomicBoolean = new AtomicBoolean(false) private[spark] def assertNotStopped(): Unit = { if (stopped.get()) { val activeContext = SparkContext.activeContext.get() val activeCreationSite = if (activeContext == null) { "(No active SparkContext.)" } else { activeContext.creationSite.longForm } throw new IllegalStateException( s"""Cannot call methods on a stopped SparkContext. |This stopped SparkContext was created at: | |${creationSite.longForm} | |The currently active SparkContext was created at: | |$activeCreationSite """.stripMargin) } } def this() = this(new SparkConf()) def this(master: String, appName: String, conf: SparkConf) = this(SparkContext.updatedConf(conf, master, appName)) def this( master: String, appName: String, sparkHome: String = null, jars: Seq[String] = Nil, environment: Map[String, String] = Map()) = { this(SparkContext.updatedConf(new SparkConf(), master, appName, sparkHome, jars, environment)) }
    private[spark] def this(master: String, appName: String) = this(master, appName, null, Nil, Map()) private[spark] def this(master: String, appName: String, sparkHome: String) = this(master, appName, sparkHome, Nil, Map())
    private[spark] def this(master: String, appName: String, sparkHome: String, jars: Seq[String]) = this(master, appName, sparkHome, jars, Map()) // log out Spark Version in Spark driver log logInfo(s"Running Spark version $SPARK_VERSION")

    二.SparkConf配置

      初始化SparkContext时,只需要一个SparkConf配置对象作为参数即可。保存配置的SparkConf类的定义在相同目录下的SparkConf.scala文件中,它最主要的成员是一个散列表,其中Key和value的类型都是字符串类型:

      

      虽然SparkConf提供了一些简单的接口来进行配置,但其实所有的配置都以<key,value>对的形式保存在setting中,比如设置master方法就是设置了配置项spark.master。

      

      所以,使用配置文件中的spark.master配置项,或者参数列表中的--master选项,或者setMaster()方法,都可以设置Master地址,只是它们的优先级不同。

      每个JVM只允许启动一个SparkContext,否则默认会抛出异常,比如在通过spark-shell启动的交互式编程环境下,已经默认创建了一个名为sc的SparkContext对象,如果直接创建一个StreamingContext对象,则会报错。一个简单的解决办法是先停止默认的sc。

      当然,也可以通过设置spark.driver.allowMultipleContext为true来忽略这个错误,如下:

      

    三.初始化过程

      SparkContext在构造的过程中,已经完成了各项服务的启动。因为Scala语法的特点,所有构造函数都会调用默认的构造函数,而默认构造函数的代码直接在类定义中。除了初始化各类配置、日志之外,最重要的初始化操作之一是启动Task调度器和DAG调度器,代码如下:

      

      DAG调度与Task调度的区别是,DAG是高层次的调度,为每个Job绘制出一个有向无环图,跟踪各Stage的输出,计算完成Job的最短路径,并将Task提交给Task调度器来执行。而Task调度器只负责接受DAG调度器的请求,负责Task的实际调度执行,所以DAGScheduler的初始化必须在Task调度器之后。

      DAG与Task这种分离设计的好处是,Spark可以灵活设计自己的DAG调度,同时还能与其他资源调度系统结合,比如YARN,Mesos等。

      Task调度器本身的创建在createTaskScheduler函数中进行。根据Spark程序提交时指定的不同模式,可以启动不同类型的调度器。并且出于容错考虑,createTaskScheduler会返回一主一备两个调度器。以YARN cluster模式为例,主、备调度器对应 不同类的实例,但是加载了相同的配置。代码如下:

    case masterUrl =>
            val cm = getClusterManager(masterUrl) match {
              case Some(clusterMgr) => clusterMgr
              case None => throw new SparkException("Could not parse Master URL: '" + master + "'")
            }
            try {
              val scheduler = cm.createTaskScheduler(sc, masterUrl)
              val backend = cm.createSchedulerBackend(sc, masterUrl, scheduler)
              cm.initialize(scheduler, backend)
              (backend, scheduler)
            } catch {
              case se: SparkException => throw se
              case NonFatal(e) =>
                throw new SparkException("External scheduler cannot be instantiated", e)
            }
    }

    四.其它功能接口

      SparkContext除了可以初始化环境,连接Spark集群外,还提供了非常多的功能入口,具体如下:

      1.创建RDD。所有的创建RDD的方法都在SparkContext中定义,比如parallelize和textFilenewAPIHadoopFile。

      2.RDD持久化。RDD的持久化操作方法persistRDD、unpersistRDD也在SparkContext中定义。

      3.创建共享变量。包括计数器和广播变量。

      4.stop()。停止SparkContext。

      5.runJob。提交RDD Action操作,这是所有调度执行的入口。

  • 相关阅读:
    C程序之修改Windows的控制台大小
    C程序之修改Windows的控制台颜色(转载)
    VS2010/MFC编程(对话框:模态对话框及其弹出过程)
    C/C++常用头文件及函数汇总
    vs2010点调试,显示系统找不到指定的文件
    C++之类和对象的使用(三)
    C++之类和对象的使用(二)
    idea激活方式
    Java之dom4j的简单解析和生成xml的应用
    Java之POI的excel导入导出
  • 原文地址:https://www.cnblogs.com/yszd/p/12696690.html
Copyright © 2011-2022 走看看