Day3
1、读《apache spark 源码剖析》第三章第3.2节、3.3节
因为3.3节的内容是是讲repl的,我暂时并不关系,所以这部分内容看看书就可以了
而3.2节的内容是讲SparkContext的初始化,比较重要,这部分要看完书后自己再看下源码
2、源码学习
书中3.2节讲的是SparkContext的初始化,但是我学习的版本是2.2.0,初始化是SparkSession,它和SparkContext的关系在后面学习时找出
类 org.apache.spark.repl.Main
生成sparksession的方法为 createSparkSession
首先初始化一些配置,
然后创建一个SparkSession.Builder,把配置项传入builder中
val builder = SparkSession.builder.config(conf)
然后配置对hive的支持,检测spark.sql.catalogImplementation配置项是否为hive;但即使这个配置项值为hive,如果检测到hive的类无法在当前环境加载到,也会回退回in-memory模式。
最后,调用builder的getOrCreate方法,创建SparkSession
类org.apache.spark.sql.SparkSession.Builder
先大致浏览一下这个类
options 外部传入的配置
extensions SparkSession的扩展类,可以提供方法扩展一些解析器、优化器等
userSuppliedContext 用户提供的SparkContext,如果新建SparkSession,会使用
然后看getOrCreate方法
Get the session from current thread's active session,如果有,把options参数更新进去,返回这个session
如果没有,从global session中取,如果有globalSession,把options参数更新进去,返回这个session
如果还是没有,则准备新建一个
新建SparkSession需要使用SparkContext,如果已经有用户指定的,则使用用户指定的(即上面提到的userSuppliedContext)使用用户传入的userSuppliedContext或者使用SparkContext.getOrCreate方法新建一个
如果有配置spark.sql.extensions(这个类配置一个SparkSession扩展类),则使用这个类扩展SparkSession
用刚得到的SparkContext和extensions作为构造参数,新建一个SparkSession,并且把这个session设置为global
为这个新得到的SparkContext创建一个监听器,在这个SparkContext结束时,清除global session的状态和状态监听器(SQLListener继承自SparkListener)
返回刚刚创建的SparkSession(其中包括SparkContext)
SparkSession的初始化完成
现在知道了SparkContext是作为SparkSession的构造参数,返回了SparkSession,SparkContext应该也是可用的了
上面的部分中, SparkContext.getOrCreate(sparkConf)和new SparkSession(sparkContext, None, None, extensions)的源码在接下来分析
类org.apache.spark.SparkContext
这个类有将近3000行,像上面的例子一样通读一遍再看getOrCreate方法应该也可行,但是我的记忆力笔记差,怕读完后面忘了前面,所以先大概了解一下这个类,把所有能收起的代码块都收起,最后剩下下列几个,从注释上看看他们都是大概做什么用的
class SparkContext :spark功能的主要入口,象征和spark集群的连接,可以用来在集群上创建rdd,广播变量,计数器等。一个jvm只能有一个活动的SparkContext(如果想要多个可以使用classloader)
object SparkContext:SparkContext对象包含许多隐式转换和参数
object SparkMasterRegex:一些用来解析spark master url串的正则表达式
class WritableConverter : 封装了一些方法,用来把Writable类型转换成T(e.g. `IntWritable` for `Int`),下面的三个也是
object WritableConverter :封装了一些方法,用来把Writable类型转换成T
class WritableFactory:封装了一些方法,用来把Writable类型转换成T
object WritableFactory:封装了一些方法,用来把Writable类型转换成T
先花5分钟大致浏览了一下class SparkContext 和object SparkContext有哪些方法,然后开始跟getOrCreate方法
在跟这个方法前,把object SparkContext类大致浏览一遍
getOrCreate方法里线程安全的创建一个SparkContext对象,并且把它标记成活跃SparkContext
下面看class SparkContext,这次要从头看了
创建事件监听器总线
// An asynchronous listener bus for Spark events
private[spark] val listenerBus = new LiveListenerBus(this)
设定启动spark任务的用户名优先取系统变量SPARK_USER,没有则取hadoop ugi
// Set SPARK_USER for user who is running SparkContext.
val sparkUser = Utils.getCurrentUserName()
初始化内部字段并验证可用性
创建JobProgressListener并加入监听器总线
创建SparkEnv,创建SparkEnv过程在下一段类分析中说明,可以先看一下
创建SparkStatusTracker,作用:Low-level status reporting APIs for monitoring job and stage progress
创建spark.ui并且绑定端口
创建HeartbeatReceiver用于接收心跳
创建schedulerBackend、taskScheduler、dagScheduler并开启taskScheduler
取得applicationId,并绑定到sparkui上
初始化SparkEnv的blockManager
启动metricsSystem
启动监听器总线,并且通知“环境已更新”和“应用已经启动”的消息
增加ShutdownHook,释放资源,清理系统变量等
初始化到此结束,后面的代码基本都是创建rdd以及运行job时用的api
小细节:
使用了AtomicReference类可以保证原子性地更新一个引用,后面有时间的话学习一下这个类的底层实现,看他提供的api,是一些get、set、update方法等,用法简单明了
其中使用了volatile关键字来保证线程安全
小细节
内部的SparkConf运行时无法改变
类org.apache.spark.SparkEnv
Holds all the runtime environment objects for a running Spark instance (either master or worker),
including the serializer, RpcEnv, block manager, map output tracker, etc
创建RpcEnv用于通信
val rpcEnv = RpcEnv.create(systemName, bindAddress, advertiseAddress, port, conf,
securityManager, clientMode = !isDriver)
创建序列化类
val serializer = instantiateClassFromConf[Serializer](
"spark.serializer", "org.apache.spark.serializer.JavaSerializer")
类似的,创建serializerManager、closureSerializer、broadcastManager、mapOutputTracker等
类SparkSession
初始化SharedState,session间共享,用于State shared across sessions, including the `SparkContext`, cached data, listener, and a catalog that interacts with external systems.
初始化SessionState,session独享,用于State isolated across sessions, including SQL configurations, temporary tables, registered functions, and everything else that accepts a [[org.apache.spark.sql.internal.SQLConf]].If `parentSessionState` is not null, the `SessionState` will be a copy of the parent.
取得SqlContext,向下兼容
后面的代码基本都是创建DataFram、Dataset以及运行sql时用的api
到此为止书中的第三章,也就是SparkSession的初始化过程的源码就学习过了,后面就要学习书的第四章spark作业提交