J'essaie d'exécuter un exemple du type https://github.com/Apache/spark/blob/master/examples/src/main/scala/org/Apache/spark/examples/sql/streaming/StructuredKafkaWordCount.scala. . J'ai commencé avec le guide de programmation Spark Structured Streaming à http://spark.Apache.org/docs/latest/structured-streaming-programming-guide.html .
Mon code est
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()
}
}
J'ai ajouté les fichiers sbt suivants:
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
}
}
J'ai aussi ajouté project/Assembly.sbt
addSbtPlugin("com.eed3si9n" % "sbt-Assembly" % "0.14.3")
Cela crée un pot Uber avec les pots non provided
.
Je soumets avec la ligne suivante:
spark-submit boontadata-spark-job1-Assembly-0.1.jar ks1:9092,ks2:9092,ks3:9092 subscribe sampletopic
mais j'obtiens cette erreur d'exécution:
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
Existe-t-il un moyen de savoir quelle classe n’est pas trouvée afin que je puisse effectuer une recherche dans le dépôt de maven.org pour cette classe?
Le code source lookupDataSource
semble se trouver à la ligne 543 à https://github.com/Apache/spark/blob/83a6ace0d1be44f70e768348ae6688798c84343e/sql/core/src/main/scala/org/Apache/spark/spark/spark/spark/spark /DataSource.scala mais je n’ai pas trouvé de lien direct avec la source de données Kafka ...
Le code source complet est ici: https://github.com/boontadata/boontadata-streams/tree/ad0d0134ddb7664d359c8dca40f1d16dddd94053f
J'ai essayé comme ça ça marche pour moi. Soumettez-le comme ceci et faites le moi savoir une fois que vous avez des problèmes
./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
Le problème est la section suivante dans build.sbt
:
// META-INF discarding
assemblyMergeStrategy in Assembly := {
{
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
case x => MergeStrategy.first
}
}
Il indique que toutes les entrées META-INF
doivent être supprimées, y compris le "code" qui permet aux alias de source de données (par exemple, kafka
) de fonctionner.
Mais les fichiers META-INF
sont très importants pour que kafka
(et d’autres alias de sources de données en continu) fonctionne.
Pour que l'alias kafka
fonctionne, Spark SQL utilise META-INF/services/org.Apache.spark.sql.sources.DataSourceRegister } avec l'entrée suivante:
org.Apache.spark.sql.kafka010.KafkaSourceProvider
KafkaSourceProvider
est responsable de l'enregistrementkafka
alias avec la source de données en continu appropriée, c'est-à-dire KafkaSource .
Juste pour vérifier que le code réel est effectivement disponible, mais que le "code" qui enregistre l'alias n'est pas enregistré, vous pouvez utiliser la source de données kafka
sous le nom complet (et non l'alias) comme suit:
spark.readStream.
format("org.Apache.spark.sql.kafka010.KafkaSourceProvider").
load
Vous verrez d'autres problèmes dus à des options manquantes telles que kafka.bootstrap.servers
, mais ...nous digressons.
Une solution consiste à MergeStrategy.concat
all META-INF/services/org.Apache.spark.sql.sources.DataSourceRegister
(qui créerait un uber-jar avec toutes les sources de données, y compris la source de données kafka
).
case "META-INF/services/org.Apache.spark.sql.sources.DataSourceRegister" => MergeStrategy.concat
Dans mon cas, j'ai également eu cette erreur lors de la compilation avec sbt, et la cause en était que sbt Assembly
n'incluait pas l'artefact spark-sql-kafka-0-10_2.11
dans le gros jar.
(Je serais très heureux de faire des commentaires ici. La dépendance n’étant pas une étendue, elle ne doit donc pas être considérée comme "fournie").
J'ai donc décidé de déployer un jar normal (slim) et d'inclure les dépendances avec les paramètres --jars
dans spark-submit.
Afin de rassembler toutes les dépendances au même endroit, vous pouvez ajouter retrieveManaged := true
à vos paramètres de projet sbt ou vous pouvez, dans la console sbt, émettre:
> set retrieveManaged := true
> package
Cela devrait amener toutes les dépendances dans le dossier lib_managed
.
Ensuite, vous pouvez copier tous ces fichiers (avec une commande bash, vous pouvez par exemple utiliser quelque chose comme ceci
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"
J'utilise spark 2.1 et je suis confronté au même problème, ma solution de contournement est la suivante:
1) spark-Shell --packages org.Apache.spark:spark-sql-kafka-0-10_2.11:2.1.0
2) cd ~/.ivy2/jars
vous y êtes, tous les fichiers nécessaires sont dans ce dossier
3) copier tous les fichiers JAR de ce dossier sur tous les nœuds (créer un dossier spécifique les contenant)
4) ajoutez le nom du dossier à spark.driver.extraClassPath
et spark.driver.extraClassPath
, par exemple. spark.driver.extraClassPath=/opt/jars/*:your_other_jars
5 spark-submit --class ClassNm --Other-Options YourJar.jar
fonctionne bien maintenant
Ceux d'entre vous qui construisez votre projet sur maven peuvent essayer ceci . Ajoutez la ligne mentionnée ci-dessous à votre plug-in maven-shade
META-INF/services/org.Apache.spark.sql.sources.DataSourceRegister
J'ai mis le code de plugin pour le fichier pom à titre d'exemple pour montrer où ajouter la ligne.
<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>
S'il vous plaît excuser mes compétences de mise en forme.
J'utilise gradle comme outil de construction et le plugin shadowJar pour créer le uberJar . La solution consistait simplement à ajouter un fichier.
src/main/resources/META-INF/services/org.Apache.spark.sql.sources.DataSourceRegister
au projet.
Dans ce fichier, vous devez indiquer, ligne par ligne, les noms de classe des sources de données que vous utilisez. Dans ce cas, ce serait org.Apache.spark.sql.kafka010.KafkaSourceProvider
(recherchez ce nom de classe par exemple ici ).
La raison en est que Spark utilise Java ServiceLoader dans ses mécanismes internes de gestion des dépendances.
Exemple complet ici .
Je l'ai résolu en téléchargeant le fichier jar sur le système de pilotes. À partir de là, j'ai fourni le bocal à déclencher avec l'option --jar.
A noter également que je conditionnais tout l'environnement spark 2.1 dans mon uber jar (car mon cluster est toujours en 1.6.1).
spark-submit --jar /ur/path/spark-sql-kafka-0-10_2.11:2.1.0 --class ClassNm --Other-Options YourJar.jar