ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Apache Spark 中的 ADD JAR 语句:资源管理与 Ivy 依赖注入实战指南

Apache Spark 中的 ADD JAR 语句:资源管理与 Ivy 依赖注入实战指南 Apache Spark 中的 ADD JAR 语句资源管理与 Ivy 依赖注入实战指南【免费下载链接】sparkApache Spark - A unified analytics engine for large-scale data processing项目地址: https://gitcode.com/gh_mirrors/sp/sparkADD JAR 是 Apache Spark SQL 中用于将 JAR 文件注册为会话级资源的核心语句它直接支撑着自定义 UDF、自定义 SerDe、第三方连接器等代码的按需加载。本文以 sql-ref-syntax-aux-resource-mgmt-add-jar.md 为主线结合 Spark 源码中的语法解析、命令执行与类加载链路帮助读者完整掌握 ADD JAR 的语法、参数语义、Ivy 依赖解析机制以及与之配套的资源管理语句做到能写出、能跑通、能讲清原理。语句概述ADD JAR 是什么ADD JAR用于把一个或多个 JAR 文件添加到当前会话Session的资源列表中。添加完成后该 JAR 会被注册到 SparkContext 的分布式缓存/类加载体系中使 Executor 端能够读取其中的类加载进当前会话的共享类加载器JarClassLoader使 Driver 端的 SQL 引擎能够解析到新加入的类例如 UDF 实现类、序列化器类。添加成功的 JAR 可以通过 LIST JAR 语句随时查看与ADD FILE、ADD ARCHIVE一同构成 Spark SQL 的会话资源管理能力族。值得强调的是ADD JAR 的生效范围是当前 SparkSession而不是集群全局配置。从源码注释Adds a jar to the current session so it can be used (for UDFs or serdes)见 resources.scala可以看出它的典型用途就是为本次会话补充 UDF 或序列化依赖。语法结构ADD JAR的完整语法如下ADD { JAR | JARS } file_name [ ... ]语法要点JAR与JARS等价可互换使用均表示添加一个或多个 JAR 文件file_name可以连续给出多个多个文件名之间以空格分隔Spark 会依次逐个添加该语法规则在 ANTLR 文法中由manageResource规则承载op(ADD | LIST) simpleIdentifier .*?见 SqlBaseParser.g4ADD与LIST共用同一资源管理入口与LIST JAR、ADD FILE等语句共享一套解析框架。参数详解file_name 的三种形态file_name是被添加 JAR 的定位标识可以是以下三种位置之一位置类型说明示例本地文件系统当前节点通常是提交 Spark 应用的客户端或 Driver上可访问的本地路径/tmp/test.jar、/path with space/abc.jar分布式文件系统HDFS、S3、OSS 等分布式存储上的路径hdfs://namenode:8020/user/spark/lib/foo.jarIvy URI以ivy://为协议头从 Maven/Ivy 仓库按坐标拉取的依赖坐标ivy://group:module:version其中 Ivy URI 是 Spark 对依赖坐标式资源注入的支持。Apache Ivy 是一个强调灵活性与简单性的依赖管理器Spark 将其作为 JAR 坐标解析的底层机制并额外支持两个 URI 查询参数transitive是否传递解析依赖用于控制是否下载 Ivy URI 所指向模块的传递依赖transitive dependencies参数名transitive区分大小写必须小写书写参数值true/false不区分大小写若同一 URI 中指定了多个transitive参数以最后一个为准last one wins。exclude依赖排除列表用于在下载 Ivy URI 对应 JAR 及其依赖时指定排除项取值格式为group:module多个排除项之间以英文逗号分隔如excludegroup:module,group:module该参数与transitive可同时使用以连接。完整的 Ivy URI 写法示例如下ivy://group:module:version ivy://group:module:version?transitive[true|false] ivy://group:module:version?transitive[true|false]excludegroup:module,group:module完整示例与实战用法以下示例完整覆盖了 ADD JAR 的各种常见场景可直接在 spark-sql、Spark Connect 或 Notebook 的 SQL 单元中执行-- 添加本地文件系统上的单个 JAR ADD JAR /tmp/test.jar; -- 使用双引号包裹路径 ADD JAR /path/to/some.jar; -- 使用单引号包裹路径 ADD JAR /some/other.jar; -- 路径中包含空格时必须加引号 ADD JAR /path with space/abc.jar; -- 一次添加多个 JAR引号包裹的路径中可含空格 ADD JARS /path with space/def.jar /path with space/ghi.jar; -- 通过 Ivy URI 从仓库坐标加载 ADD JAR ivy://group:module:version; -- 禁止解析传递依赖 ADD JAR ivy://group:module:version?transitivefalse; -- 启用传递依赖解析 ADD JAR ivy://group:module:version?transitivetrue; -- 排除指定 group:module 依赖同时启用传递依赖 ADD JAR ivy://group:module:version?excludegroup:moduletransitivetrue;实际使用中的经验提醒含空格、含特殊字符的路径必须使用单引号或双引号包裹否则会被按多个文件名解析路径中未显式携带协议头如file://、hdfs://时Spark 会通过Utils.resolveURI将其解析为本地路径一次ADD JARS添加的多个文件会按顺序逐一注册可在之后的LIST JAR中确认结果。源码级实现ADD JAR 背后发生了什么理解 ADD JAR 的底层链路有助于在实际排障时快速定位问题。从当前仓库源码看ADD JAR 的执行路径大致分为三步。第一步解析为 AddJarsCommandSQL 文本被 ANTLR 文法解析后ADD JAR会被翻译成物理执行计划AddJarsCommand见 resources.scalacase class AddJarsCommand(paths: Seq[String]) extends LeafRunnableCommand { override def run(sparkSession: SparkSession): Seq[Row] { paths.foreach(sparkSession.sessionState.resourceLoader.addJar(_)) Seq.empty[Row] } }可以看到ADD JARS的多文件语义在命令层被建模为paths: Seq[String]执行时对每个路径依次调用resourceLoader.addJar最终返回空结果集。解析器测试 SparkSqlParserSuite.scala 验证了多条解析路径assertEqual(ADD JAR /path2/_2/abc.jar, AddJarsCommand(Seq(/path2/_2/abc.jar))) assertEqual(ADD JAR /test/path_2/jar/abc.jar, AddJarsCommand(Seq(/test/path_2/jar/abc.jar))) assertEqual(ADD JAR \abc.jar\, AddJarsCommand(Seq(abc.jar))) assertEqual(ADD JAR /path with space/abc.jar, AddJarsCommand(Seq(/path with space/abc.jar)))这从测试侧印证了引号、空格、路径通配等边界场景的解析行为。第二步SessionResourceLoader 解析并加载命令执行时调用的是SessionState.resourceLoader。会话共享的资源加载器定义于 SessionState.scala其addJar方法完成关键工作def addJar(path: String): Unit { val uri Utils.resolveURI(path) resolveJars(uri).foreach { p session.sparkContext.addJar(p) val uri new Path(p).toUri val jarURL ... session.sharedState.jarClassLoader.addURL(jarURL) } Thread.currentThread().setContextClassLoader(session.sharedState.jarClassLoader) }该方法做了三件事Utils.resolveURI(path)把用户传入的路径字符串规范化为 URIresolveJars(uri)根据 URI 协议分派——ivy://协议走 Maven/Ivy 依赖解析其余本地、HDFS 等原样返回对解析出的每个路径先通过session.sparkContext.addJar(p)注册到 SparkContext再把对应的 URL 追加到共享的jarClassLoader并将当前线程的上下文类加载器切换到该加载器从而保证后续 SQL 就能立刻用到新 JAR 里的类。其中resolveJars对 Ivy URI 的分派逻辑为SessionState.scaladef resolveJars(path: URI): Seq[String] { path.getScheme match { case ivy DependencyUtils.resolveMavenDependencies(path) case _ path.toString :: Nil } }也就是说ivy://group:module:version这样的坐标会在DependencyUtils.resolveMavenDependencies中完成 Maven 仓库查询与依赖图解析transitive、exclude等查询参数正是在这一层被消费的。这就是为什么 ADD JAR 能仅凭一个坐标就从仓库拉取整个依赖树。第三步Executor 端与类加载sparkContext.addJar会把 JAR 分发到集群的 Executor使远端任务运行时也能加载其中类而jarClassLoader.addURL则保证 Driver 端SQL 引擎所在进程的类解析链路可用。两者结合才能让 UDF、自定义聚合、SerDe 等只存在于新 JAR 中的类型在 SQL 执行的各个阶段都被正确解析与实例化。值得一提的是ADD JAR对 Ivy 坐标的端到端行为在集成测试中也有覆盖。例如 SQLQuerySuite.scala 中包含了对ivy://org.springframework:spring-core:6.1.6?transitivefalse、ivy://org.awaitility:awaitility:4.2.1等真实坐标的 ADD JAR 调用可作为排查 Ivy 解析问题的参考用例。相关语句与资源管理家族ADD JAR 不是孤立存在的它与以下语句共同构成 Spark SQL 的资源管理体系LIST JAR列出当前会话已添加的所有 JAR 文件ADD FILE添加普通数据文件非 JAR到会话资源供任务端按文件名访问LIST FILE列出已添加的文件资源ADD ARCHIVE添加归档包如 .zip/.tar.gz到会话资源LIST ARCHIVE列出已添加的归档资源。这五类语句在文法层共享manageResource规则、在命令层共享SessionResourceLoader的分派逻辑SessionState.scalaJarResource走addJarFileResource走sparkContext.addFileArchiveResource走sparkContext.addArchive。理解这一统一模型后无论新增哪种资源类型其解析 → 注册 → 分发的大致路径都是一致的。小结ADD JAR 是 Spark SQL 会话级资源管理的基石语句核心要点可归纳为四条语法上JAR/JARS等价支持一次添加多个文件路径含空格时必须加引号file_name支持本地路径、分布式文件系统路径与 Ivy URI 三种形态Ivy URI 通过transitive是否解析传递依赖最后一个参数生效与exclude按group:module排除两个查询参数控制依赖行为其实现链路为ANTLR 文法解析 → AddJarsCommand → SessionResourceLoader.resolveJars/addJar → SparkContext.addJar JarClassLoader.addURL文档对应的源码与测试可分别从 resources.scala、SessionState.scala 与 SparkSqlParserSuite.scala 中进一步研读。【免费下载链接】sparkApache Spark - A unified analytics engine for large-scale data processing项目地址: https://gitcode.com/gh_mirrors/sp/spark创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进