Apache Spark с использованием spark-submit выдает NoSuchMethodError

Чтобы отправить приложение Spark в кластер, их документация отмечает:

Для этого создайте сборочный jar (или «uber» jar), содержащий ваш код и его зависимости. И sbt, и Maven имеют плагины сборки. При создании JAR-файлов сборки укажите Spark и Hadoop в качестве предоставленных зависимостей; их не нужно объединять, поскольку они предоставляются менеджером кластера во время выполнения. -- http://spark.apache.org/docs/latest/submitting-applications.html

Итак, я добавил подключаемый модуль Apache Maven Shade в свой файл pom.xml. (версия 3.0.0)
И я превратил область зависимости Spark в provided. (версия 2.1.0)

(Я также добавил подключаемый модуль сборки Apache Maven, чтобы убедиться, что я упаковываю все свои зависимости в банку при запуске mvn clean package. Я не уверен, действительно ли это необходимо.)


Вот как spark-submit терпит неудачу. Он выдает NoSuchMethodError для моей зависимости (обратите внимание, что код работает из локального экземпляра при компиляции внутри IntelliJ, предполагая, что provided удалено).

Exception in thread "main" java.lang.NoSuchMethodError: com.google.common.base.Stopwatch.createStarted()Lcom/google/common/base/Stopwatch;

Строка кода, выдающая ошибку, не имеет значения — это просто первая строка в моем основном методе, который создает Stopwatch, часть утилит Google Guava. (версия 21.0)

Другие онлайн-решения предполагают, что это связано с конфликтами версий Guava, но мне пока не повезло с этими предложениями. Любая помощь будет оценена по достоинству, спасибо.


person Community    schedule 22.02.2017    source источник


Ответы (3)


Если вы посмотрите на подкаталог /jars установки Spark 2.1.0, вы, скорее всего, увидите guava-14.0.1.jar. Согласно API для метода Guava Stopwatch#createStarted, который вы используете, createStarted не существовало до Guava 15.0. Скорее всего, процесс Classloader Spark находит предоставленную Spark библиотеку Guava 14.0.1 до того, как найдет библиотеку Guava 21.0, упакованную в ваш uberjar.

Одним из возможных решений является использование функции перемещения класса, предоставляемой подключаемый модуль Maven Shade (который вы уже используете для создания своего uberjar). С помощью «перемещения классов» Maven-Shade перемещает классы Guava 21.0 (необходимые для вашего кода) во время упаковки uberjar из местоположения pattern, отражающего их существующее имя пакета (например, com.google.common.base), в произвольное местоположение shadedPattern, которое вы указываете в Конфигурация затемнения (например, myguava123.com.google.common.base).

В результате старые и новые библиотеки Guava больше не имеют общего имени пакета, что позволяет избежать конфликта во время выполнения.

person sumitsu    schedule 22.02.2017
comment
Спасибо, добавление раздела relocation в плагин тени исправило ошибку. Кроме того, я смог удалить плагин сборки, и он все еще работал нормально. - person ; 22.02.2017

Скорее всего, у вас конфликт зависимостей, да.

Сначала вы можете посмотреть, есть ли у вас конфликт зависимостей, когда вы создаете свою банку. Быстрый способ — заглянуть прямо в банку, чтобы увидеть, есть ли там файл Stopwatch.class, и если, просмотрев байт-код, окажется, что там есть метод createStarted. В противном случае вы также можете перечислить дерево зависимостей и работать оттуда: https://maven.apache.org/plugins/maven-dependency-plugin/examples/resolving-conflicts-using-the-dependency-tree.html

Если это не проблема с вашей банкой, у вас может возникнуть проблема с зависимостями из-за конфликта между вашей установкой искры и вашей банкой. Загляните в папку lib и jar вашей установки spark. Там вы можете увидеть, есть ли у вас банки, которые включают альтернативную версию гуавы, которая не поддерживает метод createStarted() из секундомера.

person Maxime    schedule 22.02.2017
comment
Метод Stopwatch.createStarted() существует в банке, сейчас я проверяю, есть ли в Spark какая-либо конфликтующая версия Guava. - person ; 22.02.2017
comment
Похоже, что в Spark 2.1.0 есть guava-14.0.1.jar в каталоге jars. - person ; 22.02.2017

Примените приведенные выше ответы, чтобы решить проблему, используя следующую конфигурацию:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.1.0</version>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>shade</goal>
        </goals>
        <configuration>
            <relocations>
                <relocation>
                    <pattern>com.google.common</pattern>
                    <shadedPattern>shade.com.google.common</shadedPattern>
                </relocation>
                <relocation>
                    <pattern>com.google.thirdparty.publicsuffix</pattern>
                    <shadedPattern>shade.com.google.thirdparty.publicsuffix</shadedPattern>
                </relocation>
          </relocations>
        </configuration>
      </execution>
    </executions>
  </plugin>
person petertc    schedule 28.12.2017