IllegalAccessError в Spark, вызванный асинхронным http-клиентом

Контекст: я работаю над заданием потоковой передачи Spark, которое записывает данные в InfluxDB, используя эта библиотека. Вот окружающая среда.

  • Скала 2.11.8
  • Spark 2.1.0 (автономный кластер Dockerized)

соответствующие зависимости:

"org.apache.spark" %% "spark-core" % "2.1.0" % "provided",
"org.apache.spark" %% "spark-streaming" % "2.1.0" % "provided",
"org.apache.spark" %% "spark-streaming-kafka-0-8" % "2.1.0",
"com.paulgoldbaum" %% "scala-influxdb-client" % "0.5.2" // which uses "org.asynchttpclient" % "async-http-client" % "2.0.24"

Все компилируется и работает нормально на моем локальном компьютере, но когда я отправляю jar сборки в кластер Spark, я получаю эту ошибку в драйвере:

Exception in thread "main" java.lang.reflect.InvocationTargetException
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:498)
  at org.apache.spark.deploy.worker.DriverWrapper$.main(DriverWrapper.scala:58)
  at org.apache.spark.deploy.worker.DriverWrapper.main(DriverWrapper.scala)
Caused by: java.lang.IllegalAccessError: tried to access field io.netty.handler.ssl.JdkSslContext.SUPPORTED_CIPHERS from class io.netty.handler.ssl.NettySslPackageAccessor
  at io.netty.handler.ssl.NettySslPackageAccessor.jdkSupportedCipherSuites(NettySslPackageAccessor.java:24)
  at org.asynchttpclient.config.AsyncHttpClientConfigDefaults.defaultEnabledCipherSuites(AsyncHttpClientConfigDefaults.java:85)
  at org.asynchttpclient.DefaultAsyncHttpClientConfig$Builder.<init>(DefaultAsyncHttpClientConfig.java:635)
  at org.asynchttpclient.DefaultAsyncHttpClient.<init>(DefaultAsyncHttpClient.java:67)
  at com.paulgoldbaum.influxdbclient.HttpClient.<init>(HttpClient.scala:21)
  at com.paulgoldbaum.influxdbclient.InfluxDB$.connect(InfluxDB.scala:16)
  ...

Проблема исчезнет, ​​если я удалю код для записи в InfluxDB.

Что я узнал после некоторого осмотра, так это то, что класс io.netty.handler.ssl.NettySslPackageAccessor на самом деле принадлежит библиотеке async-http-client. Кажется, это хак-класс для доступа к защищенному члену в io.netty.handler.ssl.JdkSslContext.

Я возился с этой проблемой в течение нескольких дней. Решение, которое я получил, чтобы заставить его работать, переопределяет async-http-client на более раннюю версию, которая не включает оскорбительный код.

dependencyOverrides ++= Set("org.asynchttpclient" % "async-http-client" % "2.0.12")

Вопрос. Почему IllegalAccessError происходит только в кластере, а не в моем локальном запуске? Есть ли лучший способ решить эту проблему?

Если мой SBT может компилироваться нормально, то таких IllegalAccessError быть не должно, так что это означает, что между моим локальным кодом и кодом кластера есть различия, которые, вероятно, являются искровыми зависимостями provided, но это та же версия, что и кластер.

Я согласен оставить все как есть, но было бы лучше, если бы можно было использовать более новые версии. Или, по крайней мере, я хочу понять, почему возникает эта проблема, и избежать ее в будущем.


person tamatama    schedule 17.01.2017    source источник


Ответы (2)


Сегодня я столкнулся с той же проблемой и нашел эту проблему на github, которая объясняет проблему. В основном у вас есть несколько ClassLoaders при использовании Spark.

и io.netty.handler.ssl.NettySslPackageAccessor и io.netty.handler.ssl.JdkSslContext загружаются разными загрузчиками классов.

Если это так, то попытка доступа к статическому полю JdkSslContext.SUPPORTED_CIPHERS, относящемуся к пакету, завершится ошибкой IllegalAccessError, так как поля, относящиеся к пакету, «ограничены» на уровне ClassLoader.

О, и ваше решение также сработало для меня, спасибо.

person gcaliari    schedule 24.04.2017
comment
Имеет смысл. Кажется, тогда я ничего не мог с этим поделать. Ну что ж. Спасибо. - person tamatama; 24.04.2017

Это вызвано тем, что в вашем пути к классам есть как io.netty:netty, так и org.asynchttpclient:async-http-client. Если вы хотите использовать netty и assync-http-client, добавьте следующие зависимости в свой скрипт сборки gradle (аналогично maven pom.xml):

compile 'org.asynchttpclient:async-http-client:2.0.38' compile 'org.asynchttpclient:async-http-client-netty-utils:2.0.38'

person MUNGAI NJOROGE    schedule 31.12.2017
comment
Мне пришлось обновиться до более новой версии (2.7.0), но это сработало для меня. Спасибо! - person Franziskus Karsunke; 01.02.2019