Jenkins部署Scala Parquet写入程序报LocalFileSystem类找不到问题
问题根因
报错核心是Jenkins部署后的运行时类路径缺失Hadoop Common模块的对应类,本地运行正常是两个原因导致的假象:
- 本地IDE/sbt运行时会默认加载所有作用域(包括provided)的依赖,不会遗漏传递依赖
- Jenkins打包/部署环节要么存在依赖裁剪、类加载隔离,要么是打包插件的合并策略错误丢弃了Hadoop的SPI配置文件,要么是依赖冲突导致hadoop-common包被排除
你之前尝试的修复存在两处明显错误,导致配置完全没生效:
- 手动设置Hadoop配置时两次都赋值给
fs.hdfs.impl,本地文件系统对应的配置键是fs.file.impl - 代码里写的
getname是笔误,获取类名的正确方法名是getName(首字母大写),这段代码本身就无法正常编译运行
分步解决方案
1. 修正依赖配置,显式引入缺失模块
不要依赖传递依赖引入hadoop-common,在build.sbt里显式声明对应依赖,避免被排除规则过滤:
libraryDependencies ++= Seq( "com.github.mjakubowski84" %% "parquet4s-core" % "2.6.0", "org.apache.hadoop" % "hadoop-common" % "2.10.2", "org.apache.hadoop" % "hadoop-client" % "2.10.2" )
如果你是用sbt-assembly打胖包部署,必须添加正确的合并策略,否则META-INF/services下的Hadoop SPI服务发现文件会被覆盖,即使类存在也无法被识别加载:
assembly / assemblyMergeStrategy := { case PathList("META-INF", xs @ _*) => xs.map(_.toLowerCase) match { case "services" :: _ => MergeStrategy.concat case ("manifest.mf" :: Nil) | ("index.list" :: Nil) | ("dependencies" :: Nil) => MergeStrategy.discard case _ => MergeStrategy.first } case _ => MergeStrategy.first }
如果你是打瘦包部署,检查Jenkins的依赖拷贝逻辑,确保所有runtime作用域的依赖都被完整拷贝到服务器的lib目录,不要遗漏hadoop-common相关的jar包。
2. 修正Hadoop配置代码
把错误的配置替换成正确写法,并且主动触发类加载,避免SPI加载失败:
import org.apache.hadoop.conf.Configuration import org.apache.hadoop.fs.LocalFileSystem import org.apache.hadoop.hdfs.DistributedFileSystem // 上下文类加载器设置必须放在所有Hadoop相关类初始化之前 Thread.currentThread().setContextClassLoader(getClass.getClassLoader) val hadoopConfig = new Configuration() hadoopConfig.set("fs.hdfs.impl", classOf[DistributedFileSystem].getName) hadoopConfig.set("fs.file.impl", classOf[LocalFileSystem].getName) // 主动触发类加载,提前验证类是否存在 classOf[LocalFileSystem] classOf[DistributedFileSystem]
3. 排查服务器环境冲突
如果改完上述配置还是报错,逐一检查以下场景:
- 如果服务器本身预装了Hadoop,检查
HADOOP_HOME、全局CLASSPATH配置,确认服务器上的Hadoop版本和你依赖的2.10.2版本一致,避免类加载器优先加载了服务器上版本不兼容、不完整的Hadoop包。这种场景建议直接打胖包部署,不要依赖服务器全局的Hadoop依赖。 - 可以在代码初始化阶段加一段校验逻辑,部署后打印类的加载来源,快速定位类路径问题:
try { val localFsClass = Class.forName("org.apache.hadoop.fs.LocalFileSystem") println(s"LocalFileSystem加载成功,来源路径:${localFsClass.getProtectionDomain.getCodeSource.getLocation}") } catch { case e: ClassNotFoundException => println("运行时类路径缺失hadoop-common包,请检查Jenkins打包、部署环节的依赖拷贝逻辑") throw e }
内容的提问来源于stack exchange,提问作者Elwys
相关产品推荐
相关产品推荐

