版本:spak2.3

相关源码:org.apache.spark.SparkContext

在创建spark任务时候,往往会指定一些依赖文件,通常我们可以在spark-submit脚本使用--files /path/to/file指定来实现。

但是公司产品的架构是通过livy来调spark任务,livy的实现其实是对spark-submit的一个包装,所以如何指定依赖文件归根到底还是在spark这边。既然不能通过命令行--files指定,那在编程中怎么指定?任务在各个节点上运行时又是如何获取到这些文件的呢?

根据spark-submit的参数传递源码分析得知,spark-submit --files其实是由参数"spark.files"接收,所以在代码中可以通过sparkConf设置该参数。

比如:

SparkConf conf = new SparkConf();
conf.set("spark.files","/path/to/file");
//如果文件是放在hdfs上,可以通过conf.set("spark.files","hdfs:/path/to/file")指定,注意这里只需要加上个hdfs的schema即可,不需要ip port

spark官网关于该参数的解释:

spark.files  Comma-separated list of files to be placed in the working directory of each executor. Globs are allowed.

具体怎么读取用户指定的文件相关源码在SparkContext.scala中,如下(--jars指定依赖jar包同理):

def jars: Seq[String] = _jars
def files: Seq[String] = _files
... _jars = Utils.getUserJars(_conf)
_files = _conf.getOption("spark.files").map(_.split(",")).map(_.filter(_.nonEmpty))
.toSeq.flatten ... // Add each JAR given through the constructor
if (jars != null) {
jars.foreach(addJar)
} if (files != null) {
files.foreach(addFile)
}

addFile实现如下:

/**
* Add a file to be downloaded with this Spark job on every node.
*
* If a file is added during execution, it will not be available until the next TaskSet starts.
*
* @param path can be either a local file, a file in HDFS (or other Hadoop-supported
* filesystems), or an HTTP, HTTPS or FTP URI. To access the file in Spark jobs,
* use `SparkFiles.get(fileName)` to find its download location.
* @param recursive if true, a directory can be given in `path`. Currently directories are
* only supported for Hadoop-supported filesystems.
* 1. 文件会下载到每一个节点
* 2. 如果在运行中增加文件,那么只有到下一批taskset开始执行时有效
* 3. 文件的位置可以是本地文件,HDFS文件或者其他hadoop支持的文件系统上,HTTP,HTTPS或者FTP URI也可以。在spark jobs中可以通过
* SparkFiles.get(fileName)访问此文件
* 4. 如果要递归获取文件,那么可以给定一个目录,但是这种方式只对Hadoop-supported filesystems有效。
*/
def addFile(path: String, recursive: Boolean): Unit = {
val uri = new Path(path).toUri
val schemeCorrectedPath = uri.getScheme match {
//如果路径中不指定schema,也就是null.
//在命令行指定--files 时候,--files /home/kong/log4j.properties等同于--files local:/home/kong/log4j.properties
case null | "local" => new File(path).getCanonicalFile.toURI.toString
case _ => path
} val hadoopPath = new Path(schemeCorrectedPath)
val scheme = new URI(schemeCorrectedPath).getScheme
if (!Array("http", "https", "ftp").contains(scheme)) {
val fs = hadoopPath.getFileSystem(hadoopConfiguration)
val isDir = fs.getFileStatus(hadoopPath).isDirectory
if (!isLocal && scheme == "file" && isDir) {
throw new SparkException(s"addFile does not support local directories when not running " +
"local mode.")
}
if (!recursive && isDir) {
throw new SparkException(s"Added file $hadoopPath is a directory and recursive is not " +
"turned on.")
}
} else {
// SPARK-17650: Make sure this is a valid URL before adding it to the list of dependencies
Utils.validateURL(uri)
} val key = if (!isLocal && scheme == "file") {
env.rpcEnv.fileServer.addFile(new File(uri.getPath))
} else {
schemeCorrectedPath
}
val timestamp = System.currentTimeMillis
if (addedFiles.putIfAbsent(key, timestamp).isEmpty) {
logInfo(s"Added file $path at $key with timestamp $timestamp")
// Fetch the file locally so that closures which are run on the driver can still use the
// SparkFiles API to access files.
Utils.fetchFile(uri.toString, new File(SparkFiles.getRootDirectory()), conf,
env.securityManager, hadoopConfiguration, timestamp, useCache = false)
postEnvironmentUpdate()
}
}

在addJar和addFile方法的最后都调用了postEnvironmentUpdate方法,而且在SparkContext初始化过程的
最后也会调用postEnvironmentUpdate,代码如下:

  /** Post the environment update event once the task scheduler is ready */
private def postEnvironmentUpdate() {
if (taskScheduler != null) {
val schedulingMode = getSchedulingMode.toString
val addedJarPaths = addedJars.keys.toSeq
val addedFilePaths = addedFiles.keys.toSeq
// 通过调用SparkEnv的方法environmentDetails将环境的JVM参数、Spark 属性、系统属性、classPath等信息设置为环境明细信息。
val environmentDetails = SparkEnv.environmentDetails(conf, schedulingMode, addedJarPaths,
addedFilePaths)
// 生成SparkListenerEnvironmentUpdate事件,并投递到事件总线
val environmentUpdate = SparkListenerEnvironmentUpdate(environmentDetails)
listenerBus.post(environmentUpdate)
}
}

environmentDetails方法:

  /**
* Return a map representation of jvm information, Spark properties, system properties, and
* class paths. Map keys define the category, and map values represent the corresponding
* attributes as a sequence of KV pairs. This is used mainly for SparkListenerEnvironmentUpdate.
*/
private[spark]
def environmentDetails(
conf: SparkConf,
schedulingMode: String,
addedJars: Seq[String],
addedFiles: Seq[String]): Map[String, Seq[(String, String)]] = { import Properties._
val jvmInformation = Seq(
("Java Version", s"$javaVersion ($javaVendor)"),
("Java Home", javaHome),
("Scala Version", versionString)
).sorted // Spark properties
// This includes the scheduling mode whether or not it is configured (used by SparkUI)
val schedulerMode =
if (!conf.contains("spark.scheduler.mode")) {
Seq(("spark.scheduler.mode", schedulingMode))
} else {
Seq.empty[(String, String)]
}
val sparkProperties = (conf.getAll ++ schedulerMode).sorted // System properties that are not java classpaths
val systemProperties = Utils.getSystemProperties.toSeq
val otherProperties = systemProperties.filter { case (k, _) =>
k != "java.class.path" && !k.startsWith("spark.")
}.sorted // Class paths including all added jars and files
val classPathEntries = javaClassPath
.split(File.pathSeparator)
.filterNot(_.isEmpty)
.map((_, "System Classpath"))
val addedJarsAndFiles = (addedJars ++ addedFiles).map((_, "Added By User"))
val classPaths = (addedJarsAndFiles ++ classPathEntries).sorted Map[String, Seq[(String, String)]](
"JVM Information" -> jvmInformation,
"Spark Properties" -> sparkProperties,
"System Properties" -> otherProperties,
"Classpath Entries" -> classPaths)
}

通过 spark.files 传入spark任务依赖的文件源码分析的更多相关文章

  1. Spark技术内幕:Stage划分及提交源码分析

    http://blog.csdn.net/anzhsoft/article/details/39859463 当触发一个RDD的action后,以count为例,调用关系如下: org.apache. ...

  2. Spark大师之路:广播变量(Broadcast)源码分析

    概述 最近工作上忙死了……广播变量这一块其实早就看过了,一直没有贴出来. 本文基于Spark 1.0源码分析,主要探讨广播变量的初始化.创建.读取以及清除. 类关系 BroadcastManager类 ...

  3. 65、Spark Streaming:数据接收原理剖析与源码分析

    一.数据接收原理 二.源码分析 入口包org.apache.spark.streaming.receiver下ReceiverSupervisorImpl类的onStart()方法 ### overr ...

  4. Spark(二)【sc.textfile的分区策略源码分析】

    sparkcontext.textFile()返回的是HadoopRDD! 关于HadoopRDD的官方介绍,使用的是旧版的hadoop api ctrl+F12搜索 HadoopRDD的getPar ...

  5. 小白都能看懂的 Spring 源码揭秘之依赖注入(DI)源码分析

    目录 前言 依赖注入的入口方法 依赖注入流程分析 AbstractBeanFactory#getBean AbstractBeanFactory#doGetBean AbstractAutowireC ...

  6. Spark技术内幕: Task向Executor提交的源码解析

    在上文<Spark技术内幕:Stage划分及提交源码分析>中,我们分析了Stage的生成和提交.但是Stage的提交,只是DAGScheduler完成了对DAG的划分,生成了一个计算拓扑, ...

  7. Spark Scheduler模块源码分析之DAGScheduler

    本文主要结合Spark-1.6.0的源码,对Spark中任务调度模块的执行过程进行分析.Spark Application在遇到Action操作时才会真正的提交任务并进行计算.这时Spark会根据Ac ...

  8. Spark源码分析之三:Stage划分

    继上篇<Spark源码分析之Job的调度模型与运行反馈>之后,我们继续来看第二阶段--Stage划分. Stage划分的大体流程如下图所示: 前面提到,对于JobSubmitted事件,我 ...

  9. spark 源码分析之十七 -- Spark磁盘存储剖析

    上篇文章 spark 源码分析之十六 -- Spark内存存储剖析 主要剖析了Spark 的内存存储.本篇文章主要剖析磁盘存储. 总述 磁盘存储相对比较简单,相关的类关系图如下: 我们先从依赖类 Di ...

随机推荐

  1. c++类的创建与使用

    c++类的创建与使用 前言: 之前一直对c++的类的创建与使用不太熟悉,有些概念还是有点模糊,借着这次休息的机会整理一下对应是知识点.如有不正确的地方还希望各位读者批评指正. 一.C++中public ...

  2. PEtools PE操作工具类C++

    源码来自各大网友并非原创修改了部分函数 仅供参考(PE没源码参考应该是很吃力的) 暂未更新完持续更新中....... PETools.h //函数头 int GetFileLength(FILE *p ...

  3. java并发(二):初探syncronized

    参考博客 Java多线程系列--"基础篇"04之 synchronized关键字 synchronized基本规则 第一条 当线程访问A对象的synchronized方法和同步块的 ...

  4. Linux文件系统层次结构标准FHS

    文件系统层次结构标准(英语:Filesystem Hierarchy Standard,FHS)定义了Linux操作系统中的主要目录及目录内容.FHS由Linux基金会维护. 当前版本为3.0版,于2 ...

  5. nth-of-type()的用法

    同样的标签选择其中一个,就用nth-of-type() <img src="http://cms-bucket.nosdn.127.net/2018/10/16/ad8698e497e ...

  6. Linux centos7 日常运维——使用w查看系统负载、vmstat命令、top命令、sar命令、nload命令

    一.使用w查看系统负载 w .uptime查看系统负载,0.00表示1分钟之内负载为0 cat  /proc/cpuinfo查看cpu核数 二.vmstat命令,查看进程.cpu.memory.交换. ...

  7. Linux CentOS7 VMware克隆、虚拟机之间互连——初学笔记

    一.VMware克隆:选中我的第一个虚拟机,右键下拉菜单—管理—克隆. 弹出对话框,下一步根据提示:             完成克隆: 二.虚拟机互连: 配置第二虚拟机IP,使用:vi /etc/s ...

  8. java学习-初级入门-面向对象①-面向对象概述-结构化程序设计

    为了学习面向对象程序设计,今天我们先利用面向对象以前的知识,设计一个学生类. 要求进行结构化程序设计. 学生类: Student 要求:存储学生的基本信息(姓名.性别.学历层次和年级),实现学生信息的 ...

  9. Element 表单校验不消失问题

    由于不好的命名习惯,所以我的:rule   :ref   :model命名就是写了改,改了再写. 直到今天出现了这个毛病就是  “表单验证不消失” 比方说这里的  ‘密码不能为空’,在我已经输入了数字 ...

  10. [Codeforces #608 div2]1271D Portals

    Description You play a strategic video game (yeah, we ran out of good problem legends). In this game ...