Hadoop 3.x.x 与 JDK17 兼容性处理

2025-06-10 13:29:41.0

一、问题描述

Hadoop 3.x.x默认支持JDK8/11,但是许多大数据组件已经默认支持JDK17,例如,Spark 4.0。因此,当部署JDK17 + Hadoop 3.x.x + Spark 4.0环境时,因为Hadoop 3.x.x不支持JDK17,这时在启动YARN集群时,会失败。查看相关日志,会发现如下的错误信息:

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @1e14e2e7

二、问题剖析

这个错误是由于Java 17的强封装特性导致的。在Java 9及更高版本中,Java引入了模块系统(Jigsaw),对反射访问进行了更严格的控制。YARN 在运行时尝试使用反射访问ClassLoader.defineClass方法,但Java 17默认不允许这样的访问,因为java.base模块没有向 YARN 的未命名模块开放java.lang包。

三、解决方法

要解决这个问题,需要在 YARN 启动脚本中添加 JVM 参数,明确允许反射访问。具体步骤如下:

(1)编辑 yarn-env.sh 文件:找到 Hadoop 安装目录下的 etc/hadoop/yarn-env.sh 文件。

(2)添加 JVM 参数:在文件中添加以下行,为 ResourceManager 和 NodeManager 添加所需的 --add-opens 参数:

# 为 ResourceManager 添加 JVM 参数
export YARN_RESOURCEMANAGER_OPTS="$YARN_RESOURCEMANAGER_OPTS --add-opens java.base/java.lang=ALL-UNNAMED"

# 为 NodeManager 添加 JVM 参数
export YARN_NODEMANAGER_OPTS="$YARN_NODEMANAGER_OPTS --add-opens java.base/java.lang=ALL-UNNAMED"

--add-opens java.base/java.lang=ALL-UNNAMED 这个参数的作用是,允许未命名模块(如 YARN 组件)通过反射访问 java.base 模块中的 java.lang 包。 ALL-UNNAMED 表示对所有未命名模块开放,这是解决 Hadoop/YARN 兼容性问题的常用方法。

(3)重启 YARN 集群:先停止当前运行的 YARN 服务(sbin/stop-yarn.sh),然后重新启动(sbin/start-yarn.sh)。


《PySpark原理深入与编程实战》