簡體   English   中英

為什么 Spark 應用程序失敗並顯示“線程 ”main“中的異常 java.lang.NoClassDefFoundError: …StringDeserializer”?

[英]Why does Spark application fail with “Exception in thread ”main“ java.lang.NoClassDefFoundError: …StringDeserializer”?

我正在開發一個 Spark 應用程序,它使用 Spark 和 Java 偵聽 Kafka 流。

我使用 kafka_2.10-0.10.2.1。

我為 Kafka 屬性設置了各種參數: bootstrap.serverskey.deserializervalue.deserializer等。

我的應用程序編譯正常,但是當我提交它時,它失敗並顯示以下錯誤:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/kafka/common/serialization/StringDeserializer

我確實將StringDeserializer用於key.deserializervalue.deserializer因此它確實與我編寫應用程序的方式有關。

pom.xml使用的各種 maven 依賴項:

    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-core_2.11</artifactId>
        <version>2.1.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-streaming_2.10</artifactId>
        <version>2.1.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
        <version>2.1.1</version>
    </dependency>

我已經嘗試更新 Spark Streaming/kafka 的版本。 我在任何地方都找不到太多東西。

正如你在上面的評論中提到的

原來的問題是 uber jar 沒有正確構建。

這正是問題所在。 它確實與您如何組裝 Spark 應用程序有關,我擔心您可能選擇了 uber jar 方式。 在我看來,這是浪費你在組裝和火花提交時間上的時間。

我個人更喜歡使用--packages命令行選項,如果需要,它負責拉下所有必要的依賴項。

$ ./bin/spark-submit --help
...
  --packages                  Comma-separated list of maven coordinates of jars to include
                              on the driver and executor classpaths. Will search the local
                              maven repo, then maven central and any additional remote
                              repositories given by --repositories. The format for the
                              coordinates should be groupId:artifactId:version.
...

這使您作為 Spark 開發人員的生活變得更輕松,您不再需要等到 maven/sbt 下載依賴項並將它們組裝在一起。 它是在spark-submit時間完成的(也許這也是別人的工作!:))

你應該按如下方式spark-submit

spark-submit --packages org.apache.spark:spark-streaming-kafka-0-10_2.11:2.1.1 ...

這個額外要求的原因是spark-streaming-kafka-0-10模塊默認不包含在 Spark 的 CLASSPATH 中(因為它在大多數情況下被認為是不必要的)。 通過執行上面的--packages命令行,您可以觸發加載模塊(及其傳遞依賴項)。

您不應將該模塊捆綁在 Spark 應用程序的 uber jar 中。

火花streaming_ 2.10

這取決於 Scala 2.10

您的其他依賴項正在使用 Scala 2.11

升級版本是當前錯誤的正確解決方案。

並確保在 streaming-kafka- 0-10 中,這與您正在運行的 Kafka 版本相匹配

應用程序編譯正常,但是當我嘗試提交 spark 作業時,它顯示錯誤:線程“main”中的異常 java.lang.NoClassDefFoundError:

默認情況下,maven 在構建目標時不包含依賴 jar

原來的問題是 uber jar 沒有正確構建。 如果您想組裝應用程序並打包一個 uber jar。

src/assembly/assembly.xml創建一個程序集文件

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
    <id>bin</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <unpack>true</unpack>
            <scope>provided</scope>
        </dependencySet>
    </dependencySets>
</assembly>

並將maven-assembly-plugin添加到pom.xml


        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <descriptors>
                        <descriptor>src/assembly/assembly.xml</descriptor>
                    </descriptors>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>

如果您想向 uber jar 添加依賴項,只需向其添加提供的范圍。
在你的情況下,它會是這樣的:


    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-core_2.11</artifactId>
        <version>2.1.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-streaming_2.10</artifactId>
        <version>2.1.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-streaming-kafka-0-10_2.11</artifactId>
        <version>2.1.1</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-clients</artifactId>
        <version>0.10.2.1</version>
        <scope>provided</scope>
    </dependency>
$spark-submit --class Main application-bin.jar

如果你更喜歡,你可以使用 shade 插件來生成胖罐。 Jacek 通過 --packages 方法提出了什么。

<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

您還可以使用 maven-dependency 插件來獲取一些依賴項並將其放入 lib 目錄中的程序集中,然后將其提供給 spark。

<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.1.2</version>
                <executions>
                    <execution>
                        <id>copy</id>
                        <phase>initialize</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <artifactItems>
                        <artifactItem>
                            <groupId>org.apache.logging.log4j</groupId>
                            <artifactId>log4j-core</artifactId>
                            <version>${log4j2.version}</version>
                            <type>jar</type>
                            <overWrite>true</overWrite>
                            <outputDirectory>${project.build.directory}/log4j-v2-jars</outputDirectory>
                            <destFileName>log4j-v2-core.jar</destFileName>
                        </artifactItem>
                        <artifactItem>
                            <groupId>org.apache.logging.log4j</groupId>
                            <artifactId>log4j-api</artifactId>
                            <version>${log4j2.version}</version>
                            <type>jar</type>
                            <overWrite>true</overWrite>
                            <outputDirectory>${project.build.directory}/log4j-v2-jars</outputDirectory>
                            <destFileName>log4j-v2-api.jar</destFileName>
                        </artifactItem>
                        <artifactItem>
                            <groupId>org.apache.logging.log4j</groupId>
                            <artifactId>log4j-1.2-api</artifactId>
                            <version>${log4j2.version}</version>
                            <type>jar</type>
                            <overWrite>true</overWrite>
                            <outputDirectory>${project.build.directory}/log4j-v2-jars</outputDirectory>
                            <destFileName>log4j-v2-1.2-api.jar</destFileName>
                        </artifactItem>
                        <artifactItem>
                            <groupId>org.apache.logging.log4j</groupId>
                            <artifactId>log4j-slf4j-impl</artifactId>
                            <version>${log4j2.version}</version>
                            <type>jar</type>
                            <overWrite>true</overWrite>
                            <outputDirectory>${project.build.directory}/log4j-v2-jars</outputDirectory>
                            <destFileName>log4j-v2-slf4j-impl.jar</destFileName>
                        </artifactItem>
                    </artifactItems>
                    <outputDirectory>${project.build.directory}/wars</outputDirectory>
                    <overWriteReleases>false</overWriteReleases>
                    <overWriteSnapshots>true</overWriteSnapshots>
                </configuration>
            </plugin>

我提出這個的原因是因為也許在您的情況下(就像我的工作一樣)您的集群位於非常嚴格的防火牆后面,並且不允許 spark 在提交步驟與 nexus 對話以解決包。 在這種情況下,您確實需要在人工制品准備時處理這個問題,其中任何一個都可能對您有所幫助。

在我使用 maven-dependency 的示例中,我獲取 log4jv2 以將其傳遞給 spark 2.3,以便獲得 log4j-v2 日志輸出(您可以改為放置依賴項)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM