当前位置: 代码网 > it编程>编程语言>Java > Spark 3.5.1 升级 Java 17 异常 cannot access class sun.nio.ch.DirectBuffer

Spark 3.5.1 升级 Java 17 异常 cannot access class sun.nio.ch.DirectBuffer

2024年08月01日 Java 我要评论
使用Spark 3.5.1 升级到Java17的时候会有一个异常,异常如下。

异常说明

使用spark 3.5.1 升级到java17的时候会有一个异常,异常如下

slf4j: failed to load class "org.slf4j.impl.staticloggerbinder".
slf4j: defaulting to no-operation (nop) logger implementation
slf4j: see http://www.slf4j.org/codes.html#staticloggerbinder for further details.
exception in thread "main" java.lang.illegalaccesserror: class org.apache.spark.storage.storageutils$ (in unnamed module @0x1c88c82d) cannot access class sun.nio.ch.directbuffer (in module java.base) because module java.base does not export sun.nio.ch to unnamed module @0x1c88c82d
	at org.apache.spark.storage.storageutils$.<clinit>(storageutils.scala:213)
	at org.apache.spark.storage.blockmanagermasterendpoint.<init>(blockmanagermasterendpoint.scala:121)
	at org.apache.spark.sparkenv$.$anonfun$create$9(sparkenv.scala:358)
	at org.apache.spark.sparkenv$.registerorlookupendpoint$1(sparkenv.scala:295)
	at org.apache.spark.sparkenv$.create(sparkenv.scala:344)
	at org.apache.spark.sparkenv$.createdriverenv(sparkenv.scala:196)
	at org.apache.spark.sparkcontext.createsparkenv(sparkcontext.scala:284)
	at org.apache.spark.sparkcontext.<init>(sparkcontext.scala:483)
	at org.apache.spark.sparkcontext$.getorcreate(sparkcontext.scala:2888)
	at org.apache.spark.sql.sparksession$builder.$anonfun$getorcreate$2(sparksession.scala:1099)
	at scala.option.getorelse(option.scala:201)
	at org.apache.spark.sql.sparksession$builder.getorcreate(sparksession.scala:1093)
	at org.apache.spark.examples.javastatustrackerdemo.main(javastatustrackerdemo.java:55)

原因分析

分析下来是因为新版本的jdk是引入了模块的概念,在常规的包引入的时候是都有模块定义的
最关键的信息

cannot access class sun.nio.ch.directbuffer (in module java.base)

按照这个信息分析了一把,在java9以上的版本里面会有module-info.class这部分信息,这个是对模块的定义,当然我们没有主动去引入,这部分就是jdk默认帮我们引入的模块信息。

在这部分我们可以找到sun.nio.ch的引入范围,其实可以发现 sun.nio.ch.directbuffer的类并不在引入的范围内

module java.base {
    exports java.io;
    exports java.lang;
    exports java.lang.annotation;
    exports java.lang.constant;
    ...
    exports sun.nio.ch to
        java.management,
        jdk.crypto.cryptoki,
        jdk.incubator.foreign,
        jdk.net,
        jdk.sctp;
    }

这个其实就是一种兼容性的需求了,为了解决这种问题,jdk提供了一些启动的参数,可以强制引入,类似下面这样,其实含义就是主动开发一些内部的模块对外部使用

--add-opens=java.base/java.lang=all-unnamed
--add-opens=java.base/java.lang.invoke=all-unnamed
--add-opens=java.base/java.lang.reflect=all-unnamed
--add-opens=java.base/java.io=all-unnamed
--add-opens=java.base/java.net=all-unnamed

参数是怎么来的

另外一个问题是,怎么知道spark启动的时候都开放哪些参数呢,陆陆续续查询到资料,这个参数信息其实是在
org.apache.spark.launcher.javamoduleoptions 中定义的
spark启动的时候会追加

private static final string[] default_module_options = {
      "-xx:+ignoreunrecognizedvmoptions",
      "--add-opens=java.base/java.lang=all-unnamed",
      "--add-opens=java.base/java.lang.invoke=all-unnamed",
      "--add-opens=java.base/java.lang.reflect=all-unnamed",
      "--add-opens=java.base/java.io=all-unnamed",
      "--add-opens=java.base/java.net=all-unnamed",
      "--add-opens=java.base/java.nio=all-unnamed",
      "--add-opens=java.base/java.util=all-unnamed",
      "--add-opens=java.base/java.util.concurrent=all-unnamed",
      "--add-opens=java.base/java.util.concurrent.atomic=all-unnamed",
      "--add-opens=java.base/sun.nio.ch=all-unnamed",
      "--add-opens=java.base/sun.nio.cs=all-unnamed",
      "--add-opens=java.base/sun.security.action=all-unnamed",
      "--add-opens=java.base/sun.util.calendar=all-unnamed",
      "--add-opens=java.security.jgss/sun.security.krb5=all-unnamed"};

解决方案

在java启动的时候追加参数,问题可以解决
在这里插入图片描述

进一步追问

这个问题其实是在jira中间有记录的
可以看链接 https://issues.apache.org/jira/browse/spark-33772

我依旧纠结的情况是这个其实是在3.3.0版本就解决了,我这个可是3.5.1不应该出这个问题啊。
在这里插入图片描述

我找到了引用这段代码的地方,是在类
org.apache.spark.launcher.sparksubmitcommandbuilder.java里面

  private list<string> buildsparksubmitcommand(map<string, string> env)
    //这里构造启动参数
    ...
    if (isclientmode) {
     //这里构造客户端参数
     ...
    }
   //追加参数
    addoptionstring(cmd, javamoduleoptions.defaultmoduleoptions());
    cmd.add("org.apache.spark.deploy.sparksubmit");
    cmd.addall(buildsparksubmitargs());
    return cmd;
  }

其实上游就是构造参数的地方。

悟了

看到这里,我终于联系起来了。咋回事呢

在这里插入图片描述
我自己写的程序其实就是在main函数上面执行,所以需要添加参数什么的需要自己去指定。
这种其实就是单机模式。我们日常在启动spark程序从控制台上启动,spark-submit这种,其实是sparksubmit这个程序去帮我们拼接里面的参数,其实我们可以改变这种local模式,我们可以启动一种叫做本地的集群模式,需要改变master参数,完整代码如下:

public final class javasparkpi {
  public static void main(string[] args) throws exception {
    system.out.println(javamoduleoptions.defaultmoduleoptions());
    sparksession spark = sparksession
      .builder()
      .appname("javasparkpi")
            .master("local-cluster[8,2,1024]")
      .getorcreate();
    system.out.println(spark.sparkcontext().uiweburl());
    spark.sparkcontext().addjar("/users/zhuxuemin/spark-examples-3.5.1/target/spark-examples-3.5.1-0.1-snapshot.jar"); //集群模式需要添加jar路径
    javasparkcontext jsc = new javasparkcontext(spark.sparkcontext());
    jsc.setloglevel("info");
    ...//这里是代码逻辑
  }
}

启动之后从控制台里面java命令可以看到参数:

前面这部分参数是我们自己加的
/library/java/javavirtualmachines/jdk-17.jdk/contents/home/bin/java --add-exports java.base/sun.nio.ch=all-unnamed -dfile.encoding=utf-8 -classpath 


这里中间很多jar包,下面找到参数,这部分就是spark代码自己加的
 "--add-opens=java.base/sun.nio.cs=all-unnamed" "--add-opens=java.base/sun.security.action=all-unnamed" "--add-opens=java.base/sun.util.calendar=all-unnamed" "--add-opens=java.security.jgss/sun.security.krb5=all-unnamed" "-djdk.reflect.usedirectmethodhandle=false" "org.apache.spark.executor.coarsegrainedexecutorbackend" "--driver-url" "spark://coarsegrainedscheduler@www.kube.com:50404" "--executor-id" "57" "--hostname" "192.168.31.89" "--cores" "2" "--app-id" "app-20240602104758-0000" "--worker-url" "spark://worker@192.168.31.89:50411" "--resourceprofileid" "0"

这里面的逻辑就是我们启动的main函数,会按照分布式的模式去启动worker,启动之前会生成命令行,就是我们看到的样子。

好了,死磕到这里了,算是可以睡着了,zzzz~~~

参考资料

翻了很多资料,贴上
https://cloud.tencent.com/developer/ask/sof/107234786
https://issues.apache.org/jira/browse/spark-33772
https://issues.apache.org/jira/browse/spark-36796
https://stackoverflow.com/questions/72724816/running-unit-tests-with-spark-3-3-0-on-java-17-fails-with-illegalaccesserror-cl
https://github.com/apache/spark/blob/v3.3.0/launcher/src/main/java/org/apache/spark/launcher/javamoduleoptions.java
https://stackoverflow.com/questions/76969857/storageutils-cannot-access-class-sun-nio-ch-directbuffer
https://spark.apache.org/docs/latest/index.html

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com