You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

构建包含Java Spark单元测试的fat jar后提交Spark任务运行失败

问题根因

你遇到的异常本质不是Spark会话资源未关闭,原因如下:

  • 你单元测试中使用了HiveContext,默认会在执行测试的工作目录下生成基于Derby的元数据存储目录metastore_db以及日志文件derby.log
  • 你执行构建打fat jar时,构建工具(Maven/Gradle)默认会把工作目录下的所有非排除文件打入jar包,而jar包内的所有文件都是只读状态
  • 提交Spark任务运行时,HiveContext会尝试读写jar包内的metastore_db,触发Derby数据库的只读权限异常
  • 单独在IDEA运行单元测试不会触发jar包构建,因此metastore_db不会被打入jar,自然不会出现运行异常

解决方案

方案1:修改构建配置排除元数据文件

在打fat jar的插件配置中添加排除规则,禁止将metastore_db、derby.log打入jar包:
Maven(以maven-assembly-plugin为例):

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <version>3.3.0</version>
  <configuration>
    <excludes>
      <exclude>metastore_db/**</exclude>
      <exclude>derby.log</exclude>
    </excludes>
    <!-- 其余原有配置 -->
  </configuration>
</plugin>

Gradle:

jar {
  exclude('metastore_db/**')
  exclude('derby.log')
  // 其余原有配置
}

方案2:单元测试指定元数据存储到临时目录

在单元测试的SparkConf中指定metastore存储路径到构建临时目录(比如Maven的target目录,Gradle的build目录,默认不会被打入jar也会每次构建自动清理):
修改你setUp方法中的SparkConf配置:

SparkConf conf = new SparkConf();
conf.setMaster("local[2]");
conf.setAppName("sparkHelperTest");
// 新增下面这行配置,指定元数据存储到target/metastore_db
conf.set("javax.jdo.option.ConnectionURL", "jdbc:derby:;databaseName=target/metastore_db;create=true");
sparkContext = new JavaSparkContext(conf);

方案3:单元测试避免使用HiveContext

如果你的单元测试不需要用到Hive相关特性,直接替换HiveContext为普通SQLContext,不会生成metastore_db目录,从根源避免问题。

临时规避方案

打fat jar时添加跳过测试的参数,避免构建阶段执行单元测试生成metastore_db:

  • Maven命令添加-DskipTests
  • Gradle命令添加-x test

内容的提问来源于stack exchange,提问作者Laodao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 04:45:08