Spark源码阅读:从Spark-Shell开始(下)
connygpt 2024-12-26 12:52 11 浏览
在上一篇文章 Spark源码阅读:从spark-shell开始(上) 中,我们发现 spark-shell 是通过 spark-submit 脚本启动的,两个脚本都只是做了一层包装,底层逻辑spark源码里的 Scala单例类 SparkSubmit。object SparkSubmit 负责提交一个spark任务,而 object repl.Main 作为参数。
为了看到真实的提交结果,我们在执行时,设置SPARK_PRINT_LAUNCH_COMMAND=1,执行结果如下:
输出到console的信息可以分为五个部分:
- 背后真正的启动命令
- 初始化 Logging 的输出
- 初始化 repl 命令行的输出:预加载类/配置,初始化SparkSession
- 打印Welcome
- 交互式命令行开始接收输入
启动命令比较简单,java 执行 object SparkSubmit 的 main函数,SparkSubmit.main 里通过反射获取 object repl.Main 的 main 函数,并触发执行:
/Library/Java/JavaVirtualMachines/jdk1.8.0_301.jdk/Contents/Home/bin/java \
-cp /Users/user/go/src/github.com/apache/spark/conf/:/Users/user/go/src/github.com/apache/spark/assembly/target/scala-2.12/jars/* \
-Dscala.usejavacp=true \
-Xmx1g org.apache.spark.deploy.SparkSubmit \
--class org.apache.spark.repl.Main \
--name Spark shell spark-shell
我们再看一下 object repl.Main 的结构。它存储了一些配置信息,还提供了创建SparkSession对象的能力。值得注意的是,sparkSession: SparkSession 和 交互式命令行里的 spark: SparkSession 是同一个对象。交互式命令行的初始化和代码执行均托管给 interp: SparkILoop 对象。
SparkILoop 实现了Spark定制版的交互式命令行。SparkILoop 继承了 scala 编译器自带的 repl 类 ILoop,所以已经具备了命令行的核心功能(读取用户输入,解释/执行代码,返回输出),它只需要定制命令行的启动逻辑即可。startup() 函数中对这段逻辑有完整的实现,后面我们着重阅读这部分代码。
上面这张图左侧是 SparkILoop 的结构,process方法包含了创建命令行的主干逻辑,启动阶段的逻辑包含在 startup 方法中。startup() 阶段,会按顺序创建:
- SplashLoop实例:启动后台线程,存储用户输入
- scala解释器实例:用来解释&执行用户输入的代码
- SparkSession实例:用来执行spark指令
然后返回初始化过程中的用户输入。
上图中右侧的代码中,startup() 返回的字符串,通过 pattern matching 进行检查。
Pattern Matching (模式匹配) 用来检查一个变量是否符合某种pattern,是函数式编程的标配。使用时,它可以取代 Java 里的 switch case,但能力远远不止于此。
如果初始化过程中,用户按了 Ctrl+D ,返回值是 null,命令行会退出执行。
如果输入了其他字符,loop(line) 里的 loop方法会解释并执行这行代码,并等待用户下一轮输入。loop 方法是 SparkILoop 父类 ILoop 的方法。它是一个尾递归函数,除非接收到 null,或者遇到不可恢复的异常,否则不会退出。
// class ILoop
@tailrec final def loop(line: String): LineResult = {
import LineResults._
if (line == null) EOF
else if (try processLine(line) catch crashRecovery) loop(readOneLine())
else ERR
}
private def readOneLine() = {
out.flush()
in readLine prompt
}
processLine 方法会处理新的指令。对于有很多行的代码块,解释器对象判断是否缓存代码,或取出缓存代码触发执行。
readOneLine 会尝试读取新的用户输入,如果没有,则处于等待状态。
命令行启动的主流程基本是这些。刚才我们提到,startup() 阶段,会按顺序创建:
- SplashLoop实例:初始化 console reader,并提取reader获取的第一条指令
- scala解释器实例:用来解释&执行用户输入的代码
- SparkSession实例:用来执行spark指令
下面我们看一下 startup() 的逻辑。
// 创建 SplashLoop,包含SplashReader实例和 prompt
val splash = preLoop
// 创建解释器
createInterpreter()
intp.initializeSynchronous()
// 更新配置,初始化SparkSession,执行预加载文件和代码
loopPostInit()
// 打印welcome
printWelcome()
// 提取第一行,Ctrl+D 停止执行
val line = splash.line
这些步骤走完之后,loop 方法会接管第一行输入,并处理完startup过程中用户输入的指令,同时接收新的用户输入指令。
这里我们重点看下如何初始化 SparkSession。初始化的逻辑定义在 initializeSpark 函数中。IMain intp 是一个 scala 的代码解释器,它通过 quietRun 可以执行代码块。
// class SparkILoop
def initializeSpark(): Unit = {
if (!intp.reporter.hasErrors) {
// `savingReplayStack` removes the commands from session history.
savingReplayStack {
initializationCommands.foreach(intp quietRun _)
}
} else {
throw new RuntimeException(s"Scala $versionString interpreter encountered " +
"errors during initialization")
}
}
// 初始化命令,总共5条
val initializationCommands: Seq[String] = Seq(
"""
@transient val spark = if (org.apache.spark.repl.Main.sparkSession != null) {
org.apache.spark.repl.Main.sparkSession
} else {
org.apache.spark.repl.Main.createSparkSession()
}
@transient val sc = {
val _sc = spark.sparkContext
// 打印 WebUI URL 和 application id
...
_sc
}
""",
"import org.apache.spark.SparkContext._",
"import spark.implicits._",
"import spark.sql",
"import org.apache.spark.sql.functions._"
)
initializationCommands 包含五个代码块,第一个用来初始化 spark 和 sc对象,其余用于在命令行里引入必要的package和class。这段代码执行完成,意味着我们可以在命令行里使用 spark 和 sc 对象。
值得注意的是 spark 的初始化是通过 object org.apache.spark.repl.Main 的方法实现的,而 repl.Main 是 spark-shell 的入口单例类。命令行里和的 spark 对象 和 repl.Main.sparkSession 成员变量是同一个 SparkSession,同理对 sc 和 repl.Main.sparkContext 也是一个。
spark-shell 代码的介绍就先到这里。如果你对于spark代码不熟悉,可以走单步调试,看关键步骤的执行是否符合预期。配置方式如下:
第一步:IDEA 增加 Remote JVM Debug 配置,这里我们只选择 use module class=spark-repl,其他使用默认值
第二步:启动 spark-shell前设置环境变量 SPARK_SUBMIT_OPTS
export SPARK_SUBMIT_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005
./bin/spark-shell
// spark-shell 命令会被卡在下面这一行,直到执行第三步
Listening for transport dt_socket at address: 5005
第三步:IDE 里启动 Debug
- 上一篇:Android Crash 详解
- 下一篇:图解MySQL是如何运行的
相关推荐
- Golang报表项目的Java重构过程
-
最近,完成了从原先使用Golang生成报表的工程项目,到Java项目来重构。【背景内容】最初使用Golang,主要是由于语言自身的精简性。不管是搭建HTTP服务端,还是对传统数据库的数据获取,都有...
- 不懂代码也能做出酷炫可视化大屏
-
最近在做一个数据可视化大屏项目,从指标设计、视觉设计、可视化动效到大屏硬件、开发工具整个流程,总结了一些经验和观点,想和大家分享。大屏制作工具大屏的制作,可以用代码开发或现成的可视化工具来实现。用的比...
- 爬虫界的启蒙老师,python超爽爬取入门案例分享
-
爬虫,就是授权的或公开数据的自动采集。百度,就是一只爬虫,一条百足之虫。学会爬虫,会让你以为自己离超越百度指日可待。人有多大胆,地有多大产,梦想还是要有的,万一实现了呢。人不怕有梦想,就怕不知道,不敢...
- 多亏这几个工具,我终于搞懂了数据分析怎么做
-
说起来,数据分析这东西之前真是让我头疼不已,感觉就像是个无解的迷宫。但多亏这几个工具,竟然帮我打开了这扇大门,让我终于搞明白了数据分析是怎么一回事。数据分析可不仅仅是个简单的任务,它涉及数据收集、处理...
- 主流富文本编辑器推荐,网站编辑器排名不分先后及特点
-
富文本编辑器(RichTextEditor,简称RTE)是一种提供类似于MicrosoftWord编辑功能的工具,在后台处理文章编辑时,深受不会编写HTML但又需要设置各种文本格式的用户喜爱,但...
- 文库系统开发全攻略:技术要点与实战案例
-
在信息爆炸的时代,文库系统作为知识管理的基石,正面临着前所未有的挑战。随着人工智能技术的崛起,我们有机会重新定义文档的存储、检索和交互方式。本文将深入探讨AI技术如何赋能文库系统,提升其智能化水平,从...
- Apache ECharts:基于JavaScript的数据可视化图表库
-
#挑战30天在头条写日记#ApacheECharts是一个由百度开源的数据可视化,凭借着良好的交互性,精巧的图表设计,得到了众多开发者的认可。而Python是一门富有表达力的语言,很适合用于数...
- 某个网站打不开,其它网站都正常怎么办?
-
前两天学echarts,结果官网打不开,其它网站都能正常打开,自己家里的网络打不开echarts官网,把echarts官网地址发给朋友都能打开,然后综合网上查看的资料,确定是dns的问题,有两种方法...
- ECharts 水球图
-
水球图是一种适合于展现单个百分比数据的图表类型,ECharts的水球图插件使你能够通过非常简单的配置,实现酷炫的数据展示效果。那么,今天我们就一起来学习一下,如何使用ECharts水球图。第一步...
- 用echarts画图表好,还是dhtmlxGantt画图表好?实战验结果
-
事情是这样的早些时候,我接到了一个需求,说要将项目里程碑用甘特图展示,一脸懵逼的我先是搜一下什么是“甘特图”:From百度百科:甘特图(Ganttchart)又称为横道图、条状图(Barch...
- 轻量级 Markdown 写作工具:One Markdown
-
大家好,我是oulvhai,MWeb的作者,MWeb是macOS和iOS/iPadOS下的Markdown写作/记笔记/静态博客生成软件。所以简单地来说我就是专门做ma...
- 【大屏可视化组态编辑器】图表
-
大屏中的图表大使用的是开源可视化图表库Echarts在线编辑:https://v.le5le.com/使用1.在html中引入echarts资源包<scriptsrc="ech...
- 20多个好用的 Vue 组件库,请查收!
-
每日一荐:Freemen,程序员自己的求职招聘软件,赶紧下载收藏一波,留着下次跳槽用。在本文中,我们将探讨一些最常见的vuejs组件。你可以收藏一波。VueTables-2地址:https://g...
- 弃用 Echarts,推荐选择Vue Data UI!
-
各位网友大家好,今天,我要向大家隆重推荐一款令人惊艳的可视化图表库——VueDataUI,一个赋予用户权力的数据可视化Vue3组件库。前言VueDataUI诞生于一个问题:如果你的仪表板...
- Echarts仿电梯运行图
-
本文适合有一定Echarts基础的人员,至少可以面向API编程。场景假设我们有这样一个需求:实现一个柱状图,柱状图中间有一个小块表示电梯,柱状图本身作为建筑物。而且电梯需要上下运行动画。实现工具优先选...
- 一周热门
- 最近发表
- 标签列表
-
- kubectlsetimage (56)
- mysqlinsertoverwrite (53)
- addcolumn (54)
- helmpackage (54)
- varchar最长多少 (61)
- 类型断言 (53)
- protoc安装 (56)
- jdk20安装教程 (60)
- rpm2cpio (52)
- 控制台打印 (63)
- 401unauthorized (51)
- vuexstore (68)
- druiddatasource (60)
- 企业微信开发文档 (51)
- rendertexture (51)
- speedphp (52)
- gitcommit-am (68)
- bashecho (64)
- str_to_date函数 (58)
- yum下载包及依赖到本地 (72)
- jstree中文api文档 (59)
- mvnw文件 (58)
- rancher安装 (63)
- nginx开机自启 (53)
- .netcore教程 (53)