如何在Spark 2.1项目中兼容最新版aws-java-sdk?
解决Spark 2.1与最新aws-java-sdk共存的方案
Spark 2.1 确实和 Hadoop 2.7.3 绑定了 aws-java-sdk 1.7.4——这是因为当时 Hadoop 的 S3A 等云存储集成完全依赖这个版本的 SDK。要在同一个 Maven 项目里让 Spark 任务和使用最新 AWS SDK 的应用共存,核心思路是类隔离或可控的依赖覆盖,下面是几个可行的方案:
方案1:使用 Maven Shade 插件做阴影包(最推荐)
这是解决依赖冲突最稳妥的方式,通过重命名你业务代码中使用的 AWS SDK 包路径,让它和 Spark 自带的旧版本 SDK 完全隔离,互不干扰。
具体配置步骤:
- 在你的 Maven 项目中,给业务模块添加
maven-shade-plugin配置,将 AWS SDK 的包路径重定位到自定义的命名空间:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <relocations> <!-- 重命名AWS SDK的核心包 --> <relocation> <pattern>com.amazonaws</pattern> <shadedPattern>com.yourproject.shaded.amazonaws</shadedPattern> </relocation> <!-- 重命名AWS SDK v2的包(如果使用v2版本) --> <relocation> <pattern>software.amazon.awssdk</pattern> <shadedPattern>com.yourproject.shaded.software.amazon.awssdk</shadedPattern> </relocation> </relocations> <!-- 排除Spark已经自带的依赖,避免重复打包 --> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>org.apache.spark:*</exclude> <exclude>org.apache.hadoop:*</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin> </plugins> </build>
- 打包后,你的业务代码会使用重命名后的
com.yourproject.shaded.amazonaws包,而 Spark 依然使用它自带的com.amazonaws1.7.4 版本,完全不会冲突。 - 提交 Spark 作业时,直接使用这个阴影包即可,不需要额外配置集群依赖。
方案2:集群运行时覆盖依赖(有兼容性风险)
如果你不想修改包名,可以尝试在提交 Spark 作业时,强制让集群加载最新的 AWS SDK 包,但要注意:Spark 2.1 和 Hadoop 2.7.3 的云存储逻辑是基于 1.7.4 版本开发的,最新 SDK 有大量 API 变更,可能会导致 Spark 的 S3 等操作失败。
具体操作:
- 下载最新版的 aws-java-sdk-bundle(包含所有模块的整合包)。
- 提交作业时,通过以下参数让 Spark 优先加载新 SDK:
spark-submit \ --class com.yourproject.Main \ --jars /path/to/aws-java-sdk-bundle-latest.jar \ --conf spark.driver.extraClassPath=/path/to/aws-java-sdk-bundle-latest.jar \ --conf spark.executor.extraClassPath=/path/to/aws-java-sdk-bundle-latest.jar \ your-app.jar
- 必须测试核心功能:比如 Spark 读写 S3、与 AWS 服务的交互是否正常,如果出现
NoSuchMethodError或ClassNotFoundException,说明版本不兼容,这个方案就不可行。
方案3:同一项目内的模块拆分(兼顾隔离与统一管理)
如果你不想用阴影包,也可以在同一个 Maven 项目下拆分两个子模块:
- spark-module:专门处理 Spark 任务,依赖 Spark 2.1 和 aws-java-sdk 1.7.4(使用
providedscope 继承 Spark 的依赖)。 - aws-business-module:处理其他 AWS 业务,依赖最新版的 aws-java-sdk,同样用 Shade 插件做包重定位。
- 父模块统一管理项目的版本和公共依赖,这样既不用维护两个独立项目,又实现了依赖隔离。
注意事项
- 无论用哪个方案,都要确保 Spark 核心任务的依赖(比如 Hadoop AWS 模块)不会被意外覆盖,否则会导致 Spark 云存储操作失败。
- 阴影包方案虽然配置稍复杂,但兼容性最好,几乎不会出现意外问题,是生产环境的首选。
内容的提问来源于stack exchange,提问作者horatio1701d




