web-dev-qa-db-fra.com

Pourquoi le format ("kafka") échoue-t-il avec "Impossible de trouver la source de données: kafka" (même avec uber-jar)?

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>
5
Kleyson Rios

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.

Approche d'Uber-Jar

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.

9
Jacek Laskowski

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>
0
RajashekharC