繁体   English   中英

为什么 Spark 应用程序会以“ClassNotFoundException: Failed to find data source: kafka”作为带有 sbt 程序集的 uber-jar 失败?

[英]Why does Spark application fail with “ClassNotFoundException: Failed to find data source: kafka” as uber-jar with sbt assembly?

我正在尝试运行像StructuredKafkaWordCount这样的示例。 我从Spark Structured Streaming Programming guide 开始

我的代码是

package io.boontadata.spark.job1

import org.apache.spark.sql.SparkSession

object DirectKafkaAggregateEvents {
  val FIELD_MESSAGE_ID = 0
  val FIELD_DEVICE_ID = 1
  val FIELD_TIMESTAMP = 2
  val FIELD_CATEGORY = 3
  val FIELD_MEASURE1 = 4
  val FIELD_MEASURE2 = 5

  def main(args: Array[String]) {
    if (args.length < 3) {
      System.err.println(s"""
        |Usage: DirectKafkaAggregateEvents <brokers> <subscribeType> <topics>
        |  <brokers> is a list of one or more Kafka brokers
        |  <subscribeType> sample value: subscribe
        |  <topics> is a list of one or more kafka topics to consume from
        |
        """.stripMargin)
      System.exit(1)
    }

    val Array(bootstrapServers, subscribeType, topics) = args

    val spark = SparkSession
      .builder
      .appName("boontadata-spark-job1")
      .getOrCreate()

    import spark.implicits._

    // Create DataSet representing the stream of input lines from kafka
    val lines = spark
      .readStream
      .format("kafka")
      .option("kafka.bootstrap.servers", bootstrapServers)
      .option(subscribeType, topics)
      .load()
      .selectExpr("CAST(value AS STRING)")
      .as[String]

    // Generate running word count
    val wordCounts = lines.flatMap(_.split(" ")).groupBy("value").count()

    // Start running the query that prints the running counts to the console
    val query = wordCounts.writeStream
      .outputMode("complete")
      .format("console")
      .start()

    query.awaitTermination()
  }

}

我添加了以下 sbt 文件:

构建.sbt:

name := "boontadata-spark-job1"
version := "0.1"
scalaVersion := "2.11.7"

libraryDependencies += "org.apache.spark" % "spark-core_2.11" % "2.0.2" % "provided"
libraryDependencies += "org.apache.spark" % "spark-streaming_2.11" % "2.0.2" % "provided"
libraryDependencies += "org.apache.spark" % "spark-sql_2.11" % "2.0.2" % "provided"
libraryDependencies += "org.apache.spark" % "spark-sql-kafka-0-10_2.11" % "2.0.2"
libraryDependencies += "org.apache.spark" % "spark-streaming-kafka-0-10_2.11" % "2.0.2"
libraryDependencies += "org.apache.kafka" % "kafka-clients" % "0.10.1.1"
libraryDependencies += "org.apache.kafka" % "kafka_2.11" % "0.10.1.1"

// META-INF discarding
assemblyMergeStrategy in assembly := { 
   {
    case PathList("META-INF", xs @ _*) => MergeStrategy.discard
    case x => MergeStrategy.first
   }
}

我还添加了 project/assembly.sbt

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.3")

这将使用未provided jar 创建一个 Uber jar。

我提交以下行:

spark-submit boontadata-spark-job1-assembly-0.1.jar ks1:9092,ks2:9092,ks3:9092 subscribe sampletopic

但我收到此运行时错误:

Exception in thread "main" java.lang.ClassNotFoundException: Failed to find data source: kafka. Please find packages at https://cwiki.apache.org/confluence/display/SPARK/Third+Party+Projects
        at org.apache.spark.sql.execution.datasources.DataSource.lookupDataSource(DataSource.scala:148)
        at org.apache.spark.sql.execution.datasources.DataSource.providingClass$lzycompute(DataSource.scala:79)
        at org.apache.spark.sql.execution.datasources.DataSource.providingClass(DataSource.scala:79)
        at org.apache.spark.sql.execution.datasources.DataSource.sourceSchema(DataSource.scala:218)
        at org.apache.spark.sql.execution.datasources.DataSource.sourceInfo$lzycompute(DataSource.scala:80)
        at org.apache.spark.sql.execution.datasources.DataSource.sourceInfo(DataSource.scala:80)
        at org.apache.spark.sql.execution.streaming.StreamingRelation$.apply(StreamingRelation.scala:30)
        at org.apache.spark.sql.streaming.DataStreamReader.load(DataStreamReader.scala:124)
        at io.boontadata.spark.job1.DirectKafkaAggregateEvents$.main(StreamingJob.scala:41)
        at io.boontadata.spark.job1.DirectKafkaAggregateEvents.main(StreamingJob.scala)
        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.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:736)
        at org.apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:185)
        at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:210)
        at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:124)
        at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Caused by: java.lang.ClassNotFoundException: kafka.DefaultSource
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at org.apache.spark.sql.execution.datasources.DataSource$$anonfun$5$$anonfun$apply$1.apply(DataSource.scala:132)
        at org.apache.spark.sql.execution.datasources.DataSource$$anonfun$5$$anonfun$apply$1.apply(DataSource.scala:132)
        at scala.util.Try$.apply(Try.scala:192)
        at org.apache.spark.sql.execution.datasources.DataSource$$anonfun$5.apply(DataSource.scala:132)
        at org.apache.spark.sql.execution.datasources.DataSource$$anonfun$5.apply(DataSource.scala:132)
        at scala.util.Try.orElse(Try.scala:84)
        at org.apache.spark.sql.execution.datasources.DataSource.lookupDataSource(DataSource.scala:132)
        ... 18 more
16/12/23 13:32:48 INFO spark.SparkContext: Invoking stop() from shutdown hook

有没有办法知道哪个类没有找到,以便我可以在 maven.org 存储库中搜索该类。

lookupDataSource源代码似乎位于https://github.com/apache/spark/blob/83a6ace0d1be44f70e768348ae6688798c84343e/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/的第 543 行.scala但我找不到与 Kafka 数据源的直接链接...

完整的源代码在这里: https : //github.com/boontadata/boontadata-streams/tree/ad0d0134ddb7664d359c8dca40f1d16ddd94053f

问题是build.sbt的以下部分:

// META-INF discarding
assemblyMergeStrategy in assembly := { 
   {
    case PathList("META-INF", xs @ _*) => MergeStrategy.discard
    case x => MergeStrategy.first
   }
}

它说所有META-INF都应该被丢弃,包括使数据源别名(例如kafka )工作的“代码”。

但是META-INF文件对于kafka (和其他流数据源的别名)的工作非常重要。

为了使kafka别名工作 Spark SQL 使用META-INF/services/org.apache.spark.sql.sources.DataSourceRegister和以下条目:

org.apache.spark.sql.kafka010.KafkaSourceProvider

KafkaSourceProvider 负责将kafka别名注册到适当的流数据源,即KafkaSource

只是为了检查真正的代码确实可用,但使别名注册的“代码”不是,您可以通过完全限定名称(而不是别名)使用kafka数据源,如下所示:

spark.readStream.
  format("org.apache.spark.sql.kafka010.KafkaSourceProvider").
  load

由于缺少kafka.bootstrap.servers等选项,您会看到其他问题,但是......我们离题了

一个解决方案是MergeStrategy.concat all META-INF/services/org.apache.spark.sql.sources.DataSourceRegister (这将创建一个包含所有数据源的 uber-jar,包括kafka数据源)。

case "META-INF/services/org.apache.spark.sql.sources.DataSourceRegister" => MergeStrategy.concat

我试过这样它对我有用。 像这样提交,一旦您有任何问题,请告诉我

./spark-submit --packages org.apache.spark:spark-sql-kafka-0-10_2.11:2.1.0 --class com.inndata.StructuredStreaming.Kafka --master local[*] /Users/apple/.m2/repository/com/inndata/StructuredStreaming/0.0.1SNAPSHOT/StructuredStreaming-0.0.1-SNAPSHOT.jar

在我的情况下,我在用 sbt 编译时也遇到了这个错误,原因是sbt assembly不包括作为胖 jar 一部分的spark-sql-kafka-0-10_2.11工件。

(我非常欢迎在这里发表评论。依赖项没有指定范围,所以不应该假设它是“提供的”)。

所以我改为部署一个普通的(超薄的)jar 并将依赖项和--jars参数包含到 spark-submit 中。

为了在一个地方收集所有依赖项,您可以将retrieveManaged := true添加到您的sbt 项目设置中,或者您可以在sbt 控制台中发出:

> set retrieveManaged := true
> package

这应该将所有依赖项带到lib_managed文件夹。

然后你可以复制所有这些文件(使用 bash 命令,你可以使用这样的东西

cd /path/to/your/project

JARLIST=$(find lib_managed -name '*.jar'| paste -sd , -)

spark-submit [other-args] target/your-app-1.0-SNAPSHOT.jar --jars "$JARLIST"

这是考虑到 Jacek Laskowski 的回答。

那些在 maven 上构建项目的人可以试试这个。 将下面提到的行添加到您的 maven-shade-plugin。

META-INF/services/org.apache.spark.sql.sources.DataSourceRegister

我已经放下了 pom 文件的插件代码作为示例来显示添加行的位置。


<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>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>
                            META-INF/services/org.apache.spark.sql.sources.DataSourceRegister
                        </resource>
                    </transformer>
                </transformers>
                <finalName>${project.artifactId}-${project.version}-uber</finalName>
            </configuration>
        </execution>
    </executions>
</plugin>

请原谅我的格式化技巧。

我正在使用 spark 2.1 并面临同样的问题,我的解决方法是

1) spark-shell --packages org.apache.spark:spark-sql-kafka-0-10_2.11:2.1.0

2) cd ~/.ivy2/jars在这里,所有需要的 jars 现在都在这个文件夹中

3) 将这个文件夹中的所有 jars 复制到所有节点(可以创建一个包含它们的特定文件夹)

4) 将文件夹名称添加到spark.driver.extraClassPathspark.driver.extraClassPath ,例如spark.driver.extraClassPath=/opt/jars/*:your_other_jars

5 spark-submit --class ClassNm --Other-Options YourJar.jar现在工作正常

我使用 gradle 作为构建工具和 shadowJar 插件来创建 uberJar。 解决方案只是添加一个文件

src/main/resources/META-INF/services/org.apache.spark.sql.sources.DataSourceRegister  

到项目。

在这个文件中,您需要逐行放置您使用的数据源的类名,在这种情况下它将是org.apache.spark.sql.kafka010.KafkaSourceProvider (例如在这里找到该类名)

原因是 Spark 在其内部依赖管理机制中使用了 java ServiceLoader

完整示例在这里

我通过将jar文件下载到驱动系统来解决它。 从那里,我提供了 jar 以使用 --jar 选项触发提交。

还要注意的是,我将整个 spark 2.1 环境打包在我的 uber jar 中(因为我的集群仍然在 1.6.1 上)出于某种原因,当它包含在 uber jar 中时没有被选中。

spark-submit --jar /ur/path/spark-sql-kafka-0-10_2.11:2.1.0 --class ClassNm --Other-Options YourJar.jar

虽然这是一个旧线程,但我在 Hortonworks 3.1.5 上使用 Pyspark 2.3.3 时遇到了这个问题,所以我想也许它可以帮助其他人。 Spark Streaming 与 Kafka 2 的集成需要以下 jars。

注意:请根据 Spark & Kafka 的版本下载合适的 jars。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM