web-dev-qa-db-fra.com

Résoudre les problèmes de dépendance dans Apache Spark

Les problèmes courants rencontrés lors de la création et du déploiement d'applications Spark sont les suivants:

  • Java.lang.ClassNotFoundException.
  • object x is not a member of package y erreurs de compilation.
  • Java.lang.NoSuchMethodError

Comment ceux-ci peuvent être résolus?

26
user7337271

Lors de la création et du déploiement d'applications Spark, toutes les dépendances nécessitent des versions compatibles. 

  • Version Scala . Tous les packages doivent utiliser la même version majeure de Scala (2.10, 2.11, 2.12).

    Envisagez de suivre (incorrect) build.sbt:

    name := "Simple Project"
    
    version := "1.0"
    
    libraryDependencies ++= Seq(
       "org.Apache.spark" % "spark-core_2.11" % "2.0.1",
       "org.Apache.spark" % "spark-streaming_2.10" % "2.0.1",
       "org.Apache.bahir" % "spark-streaming-Twitter_2.11" % "2.0.1"
    )
    

    Nous utilisons spark-streaming pour Scala 2.10 tandis que les paquets restants sont pour Scala 2.11. Un valide fichier pourrait être 

    name := "Simple Project"
    
    version := "1.0"
    
    libraryDependencies ++= Seq(
       "org.Apache.spark" % "spark-core_2.11" % "2.0.1",
       "org.Apache.spark" % "spark-streaming_2.11" % "2.0.1",
       "org.Apache.bahir" % "spark-streaming-Twitter_2.11" % "2.0.1"
    )
    

    mais il vaut mieux spécifier globalement la version et utiliser %%:

    name := "Simple Project"
    
    version := "1.0"
    
    scalaVersion := "2.11.7"
    
    libraryDependencies ++= Seq(
       "org.Apache.spark" %% "spark-core" % "2.0.1",
       "org.Apache.spark" %% "spark-streaming" % "2.0.1",
       "org.Apache.bahir" %% "spark-streaming-Twitter" % "2.0.1"
    )
    

    De même dans Maven:

    <project>
      <groupId>com.example</groupId>
      <artifactId>simple-project</artifactId>
      <modelVersion>4.0.0</modelVersion>
      <name>Simple Project</name>
      <packaging>jar</packaging>
      <version>1.0</version>
      <properties>
        <spark.version>2.0.1</spark.version>
      </properties> 
      <dependencies>
        <dependency> <!-- Spark dependency -->
          <groupId>org.Apache.spark</groupId>
          <artifactId>spark-core_2.11</artifactId>
          <version>${spark.version}</version>
        </dependency>
        <dependency>
          <groupId>org.Apache.spark</groupId>
          <artifactId>spark-streaming_2.11</artifactId>
          <version>${spark.version}</version>
        </dependency> 
        <dependency>
          <groupId>org.Apache.bahir</groupId>
          <artifactId>spark-streaming-Twitter_2.11</artifactId>
          <version>${spark.version}</version>
        </dependency>
      </dependencies>
    </project>
    
  • Version Spark Tous les packages doivent utiliser la même version majeure de Spark (1.6, 2.0, 2.1, ...).

    Pensez à suivre build.sbt (incorrect):

    name := "Simple Project"
    
    version := "1.0"
    
    libraryDependencies ++= Seq(
       "org.Apache.spark" % "spark-core_2.11" % "1.6.1",
       "org.Apache.spark" % "spark-streaming_2.10" % "2.0.1",
       "org.Apache.bahir" % "spark-streaming-Twitter_2.11" % "2.0.1"
    )
    

    Nous utilisons spark-core 1.6 tandis que les composants restants sont dans Spark 2.0. Un valide fichier pourrait être 

    name := "Simple Project"
    
    version := "1.0"
    
    libraryDependencies ++= Seq(
       "org.Apache.spark" % "spark-core_2.11" % "2.0.1",
       "org.Apache.spark" % "spark-streaming_2.10" % "2.0.1",
       "org.Apache.bahir" % "spark-streaming-Twitter_2.11" % "2.0.1"
    )
    

    mais il vaut mieux utiliser une variable:

    name := "Simple Project"
    
    version := "1.0"
    
    val sparkVersion = "2.0.1"
    
    libraryDependencies ++= Seq(
       "org.Apache.spark" % "spark-core_2.11" % sparkVersion,
       "org.Apache.spark" % "spark-streaming_2.10" % sparkVersion,
       "org.Apache.bahir" % "spark-streaming-Twitter_2.11" % sparkVersion
    )
    

    De même dans Maven:

    <project>
      <groupId>com.example</groupId>
      <artifactId>simple-project</artifactId>
      <modelVersion>4.0.0</modelVersion>
      <name>Simple Project</name>
      <packaging>jar</packaging>
      <version>1.0</version>
      <properties>
        <spark.version>2.0.1</spark.version>
        <scala.version>2.11</scala.version>
      </properties> 
      <dependencies>
        <dependency> <!-- Spark dependency -->
          <groupId>org.Apache.spark</groupId>
          <artifactId>spark-core_${scala.version}</artifactId>
          <version>${spark.version}</version>
        </dependency>
        <dependency>
          <groupId>org.Apache.spark</groupId>
          <artifactId>spark-streaming_${scala.version}</artifactId>
          <version>${spark.version}</version>
        </dependency> 
        <dependency>
          <groupId>org.Apache.bahir</groupId>
          <artifactId>spark-streaming-Twitter_${scala.version}</artifactId>
          <version>${spark.version}</version>
        </dependency>
      </dependencies>
    </project>
    
  • La version de Spark utilisée dans les dépendances de Spark doit correspondre à la version de Spark de l'installation de Spark. Par exemple, si vous utilisez 1.6.1 sur le cluster, vous devez utiliser 1.6.1 pour créer des fichiers JAR. Les versions mineures ne sont pas toujours acceptées.

  • La version de Scala utilisée pour construire jar doit correspondre à la version de Scala utilisée pour générer Spark déployé. Par défaut (fichiers binaires téléchargeables et versions par défaut):

    • Spark 1.x -> Scala 2.10
    • Spark 2.x -> Scala 2.11
  • Des packages supplémentaires doivent être accessibles sur les nœuds de travail s'ils sont inclus dans le fichier Fat jar. Il existe plusieurs options, notamment:

    • --jars argument pour spark-submit - pour distribuer les fichiers jar locaux.
    • --packages argument pour spark-submit - pour extraire les dépendances du référentiel Maven.

    Lors de la soumission dans le nœud du cluster, vous devez inclure application jar dans --jars.

17
user7337271

En plus de la réponse très détaillée déjà fournie par l'utilisateur7337271, si le problème résulte de l'absence de dépendances externes, vous pouvez créer un fichier jar avec vos dépendances, par exemple avec. plugin maven Assembly

Dans ce cas, veillez à marquer toutes les dépendances d'étincelles principales comme "fournies" dans votre système de génération et, comme indiqué plus haut, assurez-vous qu'elles sont en corrélation avec votre version d'étincelle d'exécution.

3
winson

Les classes de dépendance de votre application doivent être spécifiées dans l'option application-jar de votre commande de lancement. 

Plus de détails peuvent être trouvés à la Documentation Spark

Tiré de la documentation:

application-jar: chemin d'accès à un fichier jar groupé comprenant votre application et toutes les dépendances. L'URL doit être globalement visible à l'intérieur de votre cluster, par exemple, un chemin hdfs: // ou un fichier: // chemin qui est présent sur tous les nœuds

2
user7344209

Ajoutez tous les fichiers jar de spark-2.4.0-bin-hadoop2.7\spark-2.4.0-bin-hadoop2.7\jars du projet. Spark-2.4.0-bin-hadoop2.7 peut être téléchargé à partir de https://spark.Apache.org/downloads.html

0
Manideep Karthik

J'ai le build.sbt suivant 

lazy val root = (project in file(".")).
  settings(
    name := "spark-samples",
    version := "1.0",
    scalaVersion := "2.11.12",
    mainClass in Compile := Some("StreamingExample")        
  )

libraryDependencies ++= Seq(
  "org.Apache.spark" %% "spark-core" % "2.4.0",
  "org.Apache.spark" %% "spark-streaming" % "2.4.0",
  "org.Apache.spark" %% "spark-sql" % "2.4.0",
  "com.couchbase.client" %% "spark-connector" % "2.2.0" 
)

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

J'ai créé un gros fichier de mon application à l'aide du plugin sbt Assembly, mais lors de l'exécution de spark-submit, il échoue avec l'erreur suivante: 

Java.lang.NoClassDefFoundError: rx/Completable$OnSubscribe
    at com.couchbase.spark.connection.CouchbaseConnection.streamClient(CouchbaseConnection.scala:154)

Je peux voir que la classe existe dans mon gros pot: 

jar tf target/scala-2.11/spark-samples-Assembly-1.0.jar | grep 'Completable$OnSubscribe'
rx/Completable$OnSubscribe.class

pas sûr de ce que je manque ici, des indices? 

0
Sreerag

Je pense que ce problème doit résoudre un plugin Assembly. Vous devez construire un gros pot. Par exemple en sbt:

  • ajouter le fichier $PROJECT_ROOT/project/Assembly.sbt avec le code addSbtPlugin("com.eed3si9n" % "sbt-Assembly" % "0.14.0")
  • to build.sbtadded some librarieslibraryDependencies ++ = Seq ("com.some.company" %% "une-lib"% "1.0.0") ` 
  • dans sbt console, entrez "Assembly" et déployez Assembly jar 

Si vous avez besoin de plus d’informations, allez sur https://github.com/sbt/sbt-Assembly

0
dmitrybugakov