J'utilise HDP-2.6.3.0 avec le package 2.2.0 de Spark2.
J'essaie d'écrire un consommateur Kafka à l'aide de l'API Structured Streaming, mais j'obtiens le message d'erreur suivant après avoir envoyé le travail au cluster:
Exception in thread "main" Java.lang.ClassNotFoundException: Failed to find data source: kafka. Please find packages at http://spark.Apache.org/third-party-projects.html
at org.Apache.spark.sql.execution.datasources.DataSource$.lookupDataSource(DataSource.scala:553)
at org.Apache.spark.sql.execution.datasources.DataSource.providingClass$lzycompute(DataSource.scala:89)
at org.Apache.spark.sql.execution.datasources.DataSource.providingClass(DataSource.scala:89)
at org.Apache.spark.sql.execution.datasources.DataSource.sourceSchema(DataSource.scala:198)
at org.Apache.spark.sql.execution.datasources.DataSource.sourceInfo$lzycompute(DataSource.scala:90)
at org.Apache.spark.sql.execution.datasources.DataSource.sourceInfo(DataSource.scala:90)
at org.Apache.spark.sql.execution.streaming.StreamingRelation$.apply(StreamingRelation.scala:30)
at org.Apache.spark.sql.streaming.DataStreamReader.load(DataStreamReader.scala:150)
at com.example.KafkaConsumer.main(KafkaConsumer.Java:21)
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:782)
at org.Apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:180)
at org.Apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:205)
at org.Apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:119)
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$22$anonfun$apply$14.apply(DataSource.scala:537)
at org.Apache.spark.sql.execution.datasources.DataSource$anonfun$22$anonfun$apply$14.apply(DataSource.scala:537)
at scala.util.Try$.apply(Try.scala:192)
at org.Apache.spark.sql.execution.datasources.DataSource$anonfun$22.apply(DataSource.scala:537)
at org.Apache.spark.sql.execution.datasources.DataSource$anonfun$22.apply(DataSource.scala:537)
at scala.util.Try.orElse(Try.scala:84)
at org.Apache.spark.sql.execution.datasources.DataSource$.lookupDataSource(DataSource.scala:537)
... 17 more
En suivant la commande spark-submit
:
$SPARK_HOME/bin/spark-submit \
--master yarn \
--deploy-mode client \
--class com.example.KafkaConsumer \
--executor-cores 2 \
--executor-memory 512m \
--driver-memory 512m \
sample-kafka-consumer-0.0.1-SNAPSHOT.jar
Mon code Java:
package com.example;
import org.Apache.spark.sql.Dataset;
import org.Apache.spark.sql.Row;
import org.Apache.spark.sql.SparkSession;
public class KafkaConsumer {
public static void main(String[] args) {
SparkSession spark = SparkSession
.builder()
.appName("kafkaConsumerApp")
.getOrCreate();
Dataset<Row> ds = spark
.readStream()
.format("kafka")
.option("kafka.bootstrap.servers", "dog.mercadoanalitico.com.br:6667")
.option("subscribe", "my-topic")
.load();
}
}
pom.xml:
<project xmlns="http://maven.Apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.Apache.org/POM/4.0.0 http://maven.Apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>sample-kafka-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<!-- spark -->
<dependency>
<groupId>org.Apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.Apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.Apache.spark</groupId>
<artifactId>spark-sql-kafka-0-10_2.11</artifactId>
<version>2.2.0</version>
</dependency>
<!-- kafka -->
<dependency>
<groupId>org.Apache.kafka</groupId>
<artifactId>kafka_2.11</artifactId>
<version>0.10.1.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>local-maven-repo</id>
<url>file:///${project.basedir}/local-maven-repo</url>
</repository>
</repositories>
<build>
<!-- Include resources folder in the .jar -->
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
</resource>
</resources>
<plugins>
<!-- Plugin to compile the source. -->
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- Plugin to include all the dependencies in the .jar and set the main class. -->
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<!-- This filter is to workaround the problem caused by included signed jars.
Java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
-->
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer
implementation="org.Apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.KafkaConsumer</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
[MISE À JOUR] UBER-JAR
Ci-dessous la configuration utilisée dans pom.xml pour générer le uber-jar
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<!-- This filter is to workaround the problem caused by included signed jars.
Java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
-->
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer
implementation="org.Apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.KafkaConsumer</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
La source de données kafka
est un module external et n'est pas disponible par défaut pour les applications Spark.
Vous devez le définir comme une dépendance dans votre pom.xml
(comme vous l'avez fait), mais ce n'est que la toute première étape pour l'inclure dans votre application Spark.
<dependency>
<groupId>org.Apache.spark</groupId>
<artifactId>spark-sql-kafka-0-10_2.11</artifactId>
<version>2.2.0</version>
</dependency>
Avec cette dépendance, vous devez décider si vous voulez créer un soi-disant uber-jar qui regrouperait toutes les dépendances (ce qui donnerait un fichier JAR assez volumineux et rallongerait le délai de soumission). utilisez l'option --packages
(ou moins flexible --jars
) pour ajouter la dépendance au spark-submit
heure.
(Il existe d'autres options telles que le stockage des fichiers JAR requis sur Hadoop HDFS ou l'utilisation de méthodes de définition des dépendances propres à la distribution Hadoop pour les applications Spark, mais restons simples.)
Je recommanderais d'utiliser --packages
en premier et seulement quand cela fonctionne considérer les autres options.
Utilisez spark-submit --packages
pour inclure le module spark-sql-kafka-0-10 comme suit.
spark-submit --packages org.Apache.spark:spark-sql-kafka-0-10_2.11:2.2.0
Incluez les autres options de ligne de commande à votre guise.
Inclure toutes les dépendances dans un soi-disant uber-jar peut ne pas toujours fonctionner en raison de la façon dont les répertoires META-INF
sont gérés.
Pour que la source de données kafka
fonctionne (et les autres sources de données en général), vous devez vous assurer que META-INF/services/org.Apache.spark.sql.sources.DataSourceRegister
de toutes les sources de données est merged (pas replace
ou first
ou quelle que soit la stratégie que vous utilisez).
Les sources de données kafka
utilisent leur propre META-INF/services/org.Apache.spark.sql.sources.DataSourceRegister qui enregistre org.Apache.spark.sql.kafka010.KafkaSourceProvider en tant que fournisseur de source de données pour kafka
format.
Même si j'avais un problème similaire, le problème a commencé lorsque nous avons mis à niveau la version Cloudera-Spark de 2.2 -> 2.3.
Le problème était le suivant: mon fichier joker META-INF/serives/org.Apache.spark.sql.sources.DataSourceRegister était en train d’être écrasé par un fichier similaire, présent dans d’autres fichiers. Par conséquent, il n'a pas été possible de trouver l'entrée KafkaConsumer dans le fichier 'DataSourceRegister'.
Résolution: Modifier le fichier POM.xml m'a aidé.
<configuration>
<transformers>
<transformer
implementation="org.Apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>
META-INF/services/org.Apache.spark.sql.sources.DataSourceRegister
</resource>
</transformer>
</transformers>