SparkContext的初始化

SparkContext是应用启动时创建的Spark上下文对象,是进行Spark应用开发的主要接口,是Spark上层应用与底层实现的中转站(SparkContext负责给executors发送task)。

SparkContext在初始化过程中,主要涉及一下内容:

  • SparkEnv
  • DAGScheduler
  • TaskScheduler
  • SchedulerBackend
  • SparkUI

生成SparkConf

SparkContext的构造函数中最重要的入參是SparkConf。SparkContext进行初始化的时候,首先要依据初始化入參来构建SparkConf对象。进而再去创建SparkEnv。



创建SparkConf对象来管理spark应用的属性设置。

SparkConf类比較简单。是通过一个HashMap容器来管理key、value类型的属性。

下图为SparkConf类声明,当中setting变量为HashMap容器:



以下是SparkContext类中。关于SparkConf对象的拷贝过程:

创建LiveListenerBus监听器

这是典型的观察者模式,向LiveListenerBus类注冊不同类型的SparkListenerEvent事件,SparkListenerBus会遍历它的全部监听者SparkListener,然后找出事件对应的接口进行响应。

以下是SparkContext创建LiveListenerBus对象:

  // An asynchronous listener bus for Spark events
private[spark] val listenerBus = new LiveListenerBus

创建SparkEnv执行环境

在SparkEnv中创建了MapOutputTracker、MasterActor、BlockManager、CacheManager、HttpFileServer一系列对象。

下图为生成SparkEnv的代码:

SparkEnv的构造函数入參列表为:

class SparkEnv (
val executorId: String,
val actorSystem: ActorSystem,
val serializer: Serializer,
val closureSerializer: Serializer,
val cacheManager: CacheManager,
val mapOutputTracker: MapOutputTracker,
val shuffleManager: ShuffleManager,
val broadcastManager: BroadcastManager,
val blockTransferService: BlockTransferService,
val blockManager: BlockManager,
val securityManager: SecurityManager,
val httpFileServer: HttpFileServer,
val sparkFilesDir: String,
val metricsSystem: MetricsSystem,
val shuffleMemoryManager: ShuffleMemoryManager,
val outputCommitCoordinator: OutputCommitCoordinator,
val conf: SparkConf) extends Logging

这里说明几个入參的作用:

  • cacheManager: 用于存储中间计算结果
  • mapOutputTracker: 用来缓存MapStatus信息。并提供从MapOutputMaster获取信息的功能
  • shuffleManager: 路由维护表
  • broadcastManager: 广播
  • blockManager: 块管理
  • securityManager: 安全管理
  • httpFileServer: 文件存储服务器

    *l sparkFilesDir: 文件存储文件夹
  • metricsSystem: 測量
  • conf: 配置文件

创建SparkUI

以下是SparkContext初始化SparkUI的代码:

当中。在SparkUI对象初始化函数中,注冊了StorageStatusListener监听器,负责监听Storage的变化及时的展示到Spark web页面上。

attachTab方法中加入对象正是我们在Spark Web页面中看到的那个标签。

  /** Initialize all components of the server. */
def initialize() {
attachTab(new JobsTab(this))
val stagesTab = new StagesTab(this)
attachTab(stagesTab)
attachTab(new StorageTab(this))
attachTab(new EnvironmentTab(this))
attachTab(new ExecutorsTab(this))
attachHandler(createStaticHandler(SparkUI.STATIC_RESOURCE_DIR, "/static"))
attachHandler(createRedirectHandler("/", "/jobs", basePath = basePath))
attachHandler(
createRedirectHandler("/stages/stage/kill", "/stages", stagesTab.handleKillRequest))
}

创建TaskScheduler和DAGScheduler并启动执行

在SparkContext中, 最基本的初始化工作就是创建TaskScheduler和DAGScheduler, 这两个就是Spark的核心所在。

Spark的设计很的干净, 把整个DAG抽象层从实际的task执行中剥离了出来DAGScheduler, 负责解析spark命令,生成stage, 形成DAG, 终于划分成tasks, 提交给TaskScheduler, 他仅仅完毕静态分析TaskScheduler,专门负责task执行, 他仅仅负责资源管理, task分配, 执行情况的报告。

这样设计的优点, 就是Spark能够通过提供不同的TaskScheduler简单的支持各种资源调度和执行平台

以下代码是依据Spark的执行模式来选择对应的SchedulerBackend,同一时候启动TaskScheduler:



当中。createTaskScheduler最为关键的一点就是依据master变量来推断Spark当前的部署方式,进而生成对应的SchedulerBackend的不同子类。创建的SchedulerBackend放置在TaskScheduler中,在兴许的Task分发过程中扮演着重要角色。

TaskScheduler.start的目的是启动对应的SchedulerBackend,并启动定时器进行检測。以下是该函数源代码(定义在TaskSchedulerImpl.scala文件里):

  override def start() {
backend.start() if (!isLocal && conf.getBoolean("spark.speculation", false)) {
logInfo("Starting speculative execution thread")
import sc.env.actorSystem.dispatcher
sc.env.actorSystem.scheduler.schedule(SPECULATION_INTERVAL milliseconds,
SPECULATION_INTERVAL milliseconds) {
Utils.tryOrExit { checkSpeculatableTasks() }
}
}
}

加入EventLoggingListener监听器

这个默认是关闭的,能够通过spark.eventLog.enabled配置开启。

它主要功能是以json格式记录发生的事件:

  // Optionally log Spark events
private[spark] val eventLogger: Option[EventLoggingListener] = {
if (isEventLogEnabled) {
val logger =
new EventLoggingListener(applicationId, eventLogDir.get, conf, hadoopConfiguration)
logger.start()
listenerBus.addListener(logger)
Some(logger)
} else None
}

加入SparkListenerEvent事件

往LiveListenerBus中加入了SparkListenerEnvironmentUpdate、SparkListenerApplicationStart两类事件,对这两种事件监听的监听器就会调用onEnvironmentUpdate、onApplicationStart方法进行处理。

  setupAndStartListenerBus()
postEnvironmentUpdate()
postApplicationStart()

SparkContext类中的关键函数

textFile

要加载被处理的数据, 最经常使用的textFile, 事实上就是生成HadoopRDD, 作为起始的RDD

  /**
* Read a text file from HDFS, a local file system (available on all nodes), or any
* Hadoop-supported file system URI, and return it as an RDD of Strings.
*/
def textFile(path: String, minPartitions: Int = defaultMinPartitions): RDD[String] = {
assertNotStopped()
hadoopFile(path, classOf[TextInputFormat], classOf[LongWritable], classOf[Text],
minPartitions).map(pair => pair._2.toString).setName(path)
} /** Get an RDD for a Hadoop file with an arbitrary InputFormat
*
* '''Note:''' Because Hadoop's RecordReader class re-uses the same Writable object for each
* record, directly caching the returned RDD or directly passing it to an aggregation or shuffle
* operation will create many references to the same object.
* If you plan to directly cache, sort, or aggregate Hadoop writable objects, you should first
* copy them using a `map` function.
*/
def hadoopFile[K, V](
path: String,
inputFormatClass: Class[_ <: InputFormat[K, V]],
keyClass: Class[K],
valueClass: Class[V],
minPartitions: Int = defaultMinPartitions
): RDD[(K, V)] = {
assertNotStopped()
// A Hadoop configuration can be about 10 KB, which is pretty big, so broadcast it.
val confBroadcast = broadcast(new SerializableWritable(hadoopConfiguration))
val setInputPathsFunc = (jobConf: JobConf) => FileInputFormat.setInputPaths(jobConf, path)
new HadoopRDD(
this,
confBroadcast,
Some(setInputPathsFunc),
inputFormatClass,
keyClass,
valueClass,
minPartitions).setName(path)
}

runJob

关键在于调用了dagScheduler.runJob

  /**
* Run a function on a given set of partitions in an RDD and pass the results to the given
* handler function. This is the main entry point for all actions in Spark. The allowLocal
* flag specifies whether the scheduler can run the computation on the driver rather than
* shipping it out to the cluster, for short actions like first().
*/
def runJob[T, U: ClassTag](
rdd: RDD[T],
func: (TaskContext, Iterator[T]) => U,
partitions: Seq[Int],
allowLocal: Boolean,
resultHandler: (Int, U) => Unit) {
if (stopped) {
throw new IllegalStateException("SparkContext has been shutdown")
}
val callSite = getCallSite
val cleanedFunc = clean(func)
logInfo("Starting job: " + callSite.shortForm)
if (conf.getBoolean("spark.logLineage", false)) {
logInfo("RDD's recursive dependencies:\n" + rdd.toDebugString)
}
dagScheduler.runJob(rdd, cleanedFunc, partitions, callSite, allowLocal,
resultHandler, localProperties.get)
progressBar.foreach(_.finishAll())
rdd.doCheckpoint()
}

说明

以上的源代码解读基于spark-1.3.1源代码project文件

转载请注明作者Jason Ding及其出处

GitCafe博客主页(http://jasonding1354.gitcafe.io/)

Github博客主页(http://jasonding1354.github.io/)

CSDN博客(http://blog.csdn.net/jasonding1354)

简书主页(http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)

Google搜索jasonding1354进入我的博客主页

【Spark】SparkContext源代码解读的更多相关文章

  1. Spark jdbc postgresql数据库连接和写入操作源代码解读

    概述:Spark postgresql jdbc 数据库连接和写入操作源代码解读.具体记录了SparkSQL对数据库的操作,通过java程序.在本地开发和执行.总体为,Spark建立数据库连接,读取数 ...

  2. Apache Beam WordCount编程实战及源代码解读

    概述:Apache Beam WordCount编程实战及源代码解读,并通过intellij IDEA和terminal两种方式调试执行WordCount程序,Apache Beam对大数据的批处理和 ...

  3. Spark SQL 源代码分析之Physical Plan 到 RDD的详细实现

    /** Spark SQL源代码分析系列文章*/ 接上一篇文章Spark SQL Catalyst源代码分析之Physical Plan.本文将介绍Physical Plan的toRDD的详细实现细节 ...

  4. ERROR actor.OneForOneStrategy: org.apache.spark.SparkContext

    今天在用Spark把Kafka的数据往ES写的时候,代码一直报错,错误信息如下: 15/10/20 17:28:56 ERROR actor.OneForOneStrategy: org.apache ...

  5. linux内核奇遇记之md源代码解读之四

    linux内核奇遇记之md源代码解读之四 转载请注明出处:http://blog.csdn.net/liumangxiong 运行阵列意味着阵列经历从无到有,建立了作为一个raid应有的属性(如同步重 ...

  6. Apache OFbiz entity engine源代码解读

    简单介绍 近期一直在看Apache OFbiz entity engine的源代码.为了能够更透彻得理解,也由于之前没有看人别人写过分析它的文章,所以决定自己来写一篇. 首先,我提出一个问题,假设你有 ...

  7. 分享:json2.js源代码解读笔记

    1. 怎样理解"json" 首先应该意识到,json是一种数据转换格式,既然是个"格式",就是个抽象的东西.它不是js对象,也不是字符串,它仅仅是一种格式,一种 ...

  8. Spark SQL 源代码分析之 In-Memory Columnar Storage 之 in-memory query

    /** Spark SQL源代码分析系列文章*/ 前面讲到了Spark SQL In-Memory Columnar Storage的存储结构是基于列存储的. 那么基于以上存储结构,我们查询cache ...

  9. Spark SQL 源代码分析系列

    从决定写Spark SQL文章的源代码分析,到现在一个月的时间,一个又一个几乎相同的结束很快,在这里也做了一个综合指数,方便阅读,下面是读取顺序 :) 第一章 Spark SQL源代码分析之核心流程 ...

随机推荐

  1. 绑定域名到 GitHub Pages

    简介 我在阿里云上注册了一个新域名:yuanzb.com,我已经在GitHub Pages上建立了自己的博客:http://yuanzb.github.io/yuanzb/.现在我希望将yuanzb. ...

  2. VMware Fault Tolerance 概述及功能

    VMware Fault Tolerance - 为您的应用程序提供全天候可用性 通过为虚拟机启用 VMware Fault Tolerance,最大限度地延长数据中心的正常运行时间,减少停机管理成本 ...

  3. 解决hibernate向mysql插入中文乱码问题(更改MySQL字符集)

    1.首先需要修改mysql数据库的配置文件my.ini,此文件放在mysql根目录下.在此文件下查找default-character-set属性,并将其值更改为utf8(注意:不是utf-8,也要注 ...

  4. js Event对象

    (事件阶段)Event Phases Event对象在event第一次触发的时候被创建出来,并且一直伴随着事件在DOM结构中流转的整个生命周期.event对象会被作为第一个参数传递给事件监听的回调函数 ...

  5. java 竖线分割字符串的问题

    java 竖线分割字符串的问题 例1: String[] paraStr = "6010;320100;A".split(";"); System.out.pr ...

  6. 大工程(bzoj 3611)

    Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道.  我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上.  在 2 个国家 a,b 之间建一条新通 ...

  7. Sql Server 事务/回滚

    ,'test1','test1') commit tran t1  ---提交事务 功能:实现begin tran 和commit tran之间的语句,任一如果出现错误,所有都不执 事务不是有错就回滚 ...

  8. [ CodeVS冲杯之路 ] P1098

     不充钱,你怎么AC? 题目:http://codevs.cn/problem/1098/ 显然就是使每堆牌达到总体的平均数,尽量使每次移动时的牌数最大,这就类似于飞行棋,将几个棋子叠起来一起走是最优 ...

  9. 颜色混合opengl--glBlendFunc函数

    http://www.cnblogs.com/ylwn817/archive/2012/09/07/2675285.html 颜色混合opengl--glBlendFunc函数 原文:http://b ...

  10. python delete数据

    #!/usr/bin/env python # -*- coding:utf-8 -*- # @Time : 2017/11/24 0:27 # @Author : lijunjiang # @Fil ...