Apache SparkとJava 17の問題:「cannot access class sun.nio.ch.DirectBuffer」の解決方法
問題の概要
Apache Spark 3.3.0をJava 17環境で実行すると、次のようなエラーが発生します:
java.lang.IllegalAccessError: class org.apache.spark.storage.StorageUtils$ (in unnamed module @0x59d016c9)
cannot access class sun.nio.ch.DirectBuffer (in module java.base) because module java.base does not export
sun.nio.ch to unnamed module @0x59d016c9
この問題は、Java 9で導入されたモジュールシステムに関連しています。Java 17では内部APIへのアクセス制限が強化され、Sparkが内部的に使用しているsun.nio.ch.DirectBuffer
クラスへのアクセスがデフォルトで禁止されているため発生します。
WARNING
公式ドキュメントではSparkがJava 17をサポートしていると記載されていますが、実際には追加のJVMオプション設定が必要です。
主要な解決方法
方法1: JVMオプションの追加(推奨)
Java 17でSparkを正常に動作させるには、必要なモジュールを開放するJVMオプションを追加する必要があります。
基本設定(最低限必要なオプション):
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
完全な設定(すべての互換性オプション):
--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
方法2: Sparkのバージョンアップ
Spark 3.3.2以降ではこの問題が部分的に改善されている場合があります:
<!-- Maven設定 -->
<spark.version>3.5.0</spark.version>
INFO
Sparkの最新バージョンを使用することで、Java 17との互換性問題が解決している可能性があります。
環境別の設定方法
コマンドラインで実行する場合
java \
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED \
-jar your-spark-app.jar
Mavenプロジェクトの場合
pom.xmlに設定を追加:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
<!-- その他の必要なオプション -->
</argLine>
</configuration>
</plugin>
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
Gradleプロジェクトの場合
build.gradleに設定を追加:
application {
applicationDefaultJvmArgs = [
"--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
]
}
tasks.test {
jvmArgs = [
"--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
]
}
IntelliJ IDEAで実行する場合
- 実行設定を開く
- 「VM options」フィールドに以下を追加:
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED
Docker環境の場合
Dockerfileに追加:
ENV JDK_JAVA_OPTIONS="--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
VS Codeで実行する場合
launch.jsonに追加:
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Main",
"request": "launch",
"mainClass": "com.spark.Main",
"vmArgs": ["--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"]
}
]
}
代替解決策
Java 11へのダウングレード
どうしても問題が解決できない場合は、Java 11を使用することを検討してください:
<!-- ビルド設定例 -->
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
TIP
多くの運用環境では依然としてJava 11がサポートされているため、実用的な選択肢となりえます。
まとめ
Apache SparkをJava 17で実行する際の「cannot access class sun.nio.ch.DirectBuffer」エラーは、JVMのモジュールシステムに関する互換性問題です。以下のいずれかの方法で解決できます:
- JVMオプションの追加 - 最も一般的な解決方法
- Sparkのバージョンアップ - 長期的な解決策
- Java 11の使用 - 確実な代替案
環境に応じて適切な方法を選択し、Sparkアプリケーションを正常に実行してください。
DANGER
本番環境では、追加するJVMオプションがセキュリティポリシーと矛盾しないことを確認してください。特に金融機関や厳格なセキュリティ要件のある環境では、システム管理者と相談することが重要です。