Почему приложение Spark терпит неудачу с "ClassNotFoundException: не удалось найти источник данных: kafka" как uber-jar с сборкой sbt?

Я пытаюсь запустить образец, например https://github.com/apache/spark/blob/master/examples/src/main/scala/org/apache/spark/examples/sql/streaming/StructuredKafkaWordCount.scala. Я начал с руководства по программированию Spark Structured Streaming по адресу http://spark.apache.org/docs/latest/structured-streaming-programming-guide.html.

Мой код

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:

build.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")

Это создает банку Uber с банками provided.

Я отправляю следующую строку:

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, по-видимому, находится в строке 543 на https://github.com/apache/spark/blob/83a6ace0d1be44f70e768348ae6688798c84343e/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/DataSource.scala, но я не смог найти прямую связь с данными Кафки источник...

Полный исходный код находится здесь: https://github.com/boontadata/boontadata-streams/tree/ad0d0134ddb7664d359c8dca40f1d16ddd94053f

Ответ 1

Я так старался, чтобы он работал на меня. Представьте это и дайте мне знать, как только у вас возникнут проблемы.

./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

Ответ 2

В моем случае я также получил эту ошибку при компиляции с помощью sbt, и причина заключалась в том, что sbt assembly не включал артефакт spark-sql-kafka-0-10_2.11 как часть жировой банки.

(Я бы очень приветствовал комментарии здесь. Зависимость не была указана в области видимости, поэтому ее нельзя считать "предоставленной" ).

Итак, я изменил развертывание стандартной (тонкой) банки и включил зависимости с параметрами --jars, чтобы исправить-отправить.

Чтобы собрать все зависимости в одном месте, вы можете добавить 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"

Ответ 3

Я решил это, загрузив файл jar в систему драйвера. Оттуда я поставил банку, чтобы исправить подачу с помощью опции -jar.

Также следует отметить, что я упаковывал всю среду искры 2.1 в моей uber jar (так как мой кластер все еще на 1.6.1) По какой-то причине его не подхватили, когда он включен в uber jar.

spark-submit --jar/ur/path/spark-sql-kafka-0-10_2.11:2.1.0 - класс ClassNm --Другие опции YourJar.jar

Ответ 4

Я использую искру 2.1 и сталкиваюсь с той же проблемой мое обходное решение

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

2) cd ~/.ivy2/jars здесь вы, все необходимые банки находятся в этой папке сейчас

3) скопируйте все банки в эту папку на все узлы (можете создать определенную папку, содержащую их)

4) добавьте имя папки в spark.driver.extraClassPath и spark.driver.extraClassPath, например. spark.driver.extraClassPath=/opt/jars/*:your_other_jars

5 spark-submit --class ClassNm --Other-Options YourJar.jar отлично работает сейчас

Ответ 5

Проблема заключается в следующем разделе в 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