Les applications Spark dépendent souvent de bibliothèques tierces Java ou Scala. Voici les méthodes recommandées pour inclure ces dépendances lorsque vous envoyez une tâche Spark à un cluster Managed Service pour Apache Spark :
Lorsque vous envoyez une tâche à partir de votre machine locale à l'aide de la
gcloud dataproc jobs submitcommande, utilisez l'option--properties spark.jars.packages=[DEPENDENCIES].
Exemple :gcloud dataproc jobs submit spark \ --cluster=my-cluster \ --region=region \ --properties=spark.jars.packages='com.google.cloud:google-cloud-translate:1.35.0,org.apache.bahir:spark-streaming-pubsub_2.11:2.2.0'
Lorsque vous envoyez une tâche directement sur votre cluster utilisez la commande
spark-submitavec le paramètre--packages=[DEPENDENCIES].
Exemple :spark-submit --packages='com.google.cloud:google-cloud-translate:1.35.0,org.apache.bahir:spark-streaming-pubsub_2.11:2.2.0'
Lorsque vous incluez des fichiers JAR ou des bundles personnalisés :
- Dépendances spécifiques à la tâche : spécifiez le chemin d'accès Cloud Storage à
votre fichier JAR à l'aide de l'option
--jars, du Google Cloud champ Fichiers JAR de la console ou du champjarFileUrisde l'API lorsque vous envoyez une tâche. - Dépendances à l'échelle du cluster : utilisez la
spark:spark.jarspropriété de cluster lors de la création du cluster (--properties="spark:spark.jars=gs://<var>your-bucket</var>/<var>your-jarfile</var>.jar").
- Dépendances spécifiques à la tâche : spécifiez le chemin d'accès Cloud Storage à
votre fichier JAR à l'aide de l'option
Éviter les conflits de dépendance
Les approches précédentes peuvent échouer si les dépendances de l'application Spark entrent en conflit avec les dépendances de Hadoop. Ce conflit peut survenir du fait que Hadoop injecte ses
dépendances dans le paramètre
classpath de l'application. Par conséquent, ses dépendances sont
prioritaires par rapport aux dépendances de l'application. Lorsqu'un conflit se produit, NoSuchMethodError ou d'autres erreurs peuvent être générées.
Exemple :
Guava
est la bibliothèque principale de Google pour Java. Elle est utilisée par de nombreuses bibliothèques et de nombreux
frameworks, y compris Hadoop. Un conflit de dépendance peut survenir si une tâche ou ses dépendances nécessitent une version de Guava plus récente que celle utilisée par Hadoop.
Hadoop v3.0 a résolu
ce problème, mais les applications qui reposent sur des versions antérieures de Hadoop requièrent la solution suivante en deux étapes pour éviter d'éventuels conflits de dépendance.
- Créez un fichier JAR unique contenant le package de l'application et toutes ses dépendances.
- Transférez les packages de dépendance en conflit dans le fichier uber JAR pour éviter que les noms de leurs chemins d'accès n'entrent en conflit avec ceux des packages de dépendance Hadoop. Plutôt que de modifier votre code, utilisez un plug-in (voir ci-dessous) pour effectuer automatiquement ce transfert (ou "ombrage") dans le cadre du processus d'empaquetage.
Créer un uber JAR ombré avec Maven
Maven est un outil de gestion de package permettant de créer des applications Java. Le plug-in Maven Scala permet de créer des applications écrites en Scala, le langage utilisé par les applications Spark. Le plug-in Maven Shade
permet de créer un fichier JAR ombré.
Vous trouverez ci-dessous un exemple de fichier de configuration pom.xml qui effectue un ombrage sur la bibliothèque Guava, située dans le package com.google.common. Cette configuration
demande à Maven de renommer le package com.google.common avec
repackaged.com.google.common et de mettre à jour toutes les références aux classes issues de
le package d'origine.
<?xml version="1.0" encoding="UTF-8"?> <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> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <groupId><!-- YOUR_GROUP_ID --></groupId> <artifactId><!-- YOUR_ARTIFACT_ID --></artifactId> <version><!-- YOUR_PACKAGE_VERSION --></version> <dependencies> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.11</artifactId> <version><!-- YOUR_SPARK_VERSION --></version> <scope>provided</scope> </dependency> <!-- YOUR_DEPENDENCIES --> </dependencies> <build> <plugins> <plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> <executions> <execution> <goals> <goal>compile</goal> <goal>testCompile</goal> </goals> </execution> </executions> <configuration> <scalaVersion><!-- YOUR_SCALA_VERSION --></scalaVersion> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass><!-- YOUR_APPLICATION_MAIN_CLASS --></mainClass> </transformer> <!-- This is needed if you have dependencies that use Service Loader. Most Google Cloud client libraries do. --> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> </transformers> <filters> <filter> <artifact>*:*</artifact> <excludes> <exclude>META-INF/maven/**</exclude> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> <relocations> <relocation> <pattern>com</pattern> <shadedPattern>repackaged.com.google.common</shadedPattern> <includes> <include>com.google.common.**</include> </includes> </relocation> </relocations> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
Pour exécuter le build :
mvn package
Remarques sur pom.xml :
- ManifestResourceTransformer
traite les attributs du fichier manifeste de l'uber JAR (
MANIFEST.MF). Le fichier manifeste peut également spécifier le point d'entrée de votre application. - Le champ d'application de Spark
est
provided, car Spark est installé sur Managed Service pour Apache Spark. - Spécifiez la version de Spark installée sur votre cluster Managed Service pour Apache Spark (consultez la liste des versions de Managed Service pour Apache Spark ). Si votre application nécessite une version de Spark différente de celle installée sur votre cluster Managed Service pour Apache Spark, vous pouvez écrire une action d'initialisation ou créer une image personnalisée qui installera la version de Spark utilisée par votre application.
- L'entrée
<filters>exclut les fichiers de signature des répertoiresMETA-INFde vos dépendances. Sans cette entrée, une exception d'exécutionjava.lang.SecurityException: Invalid signature file digest for Manifest main attributespeut se produire, car les fichiers de signature ne sont pas valides dans le contexte de votre fichier uber JAR. - Vous devrez peut-être ombrer plusieurs bibliothèques. Pour ce faire, incluez plusieurs chemins d'accès.
L'exemple suivant illustre l'ombrage des bibliothèques Guava et Protobuf :
<relocation> <pattern>com</pattern> <shadedPattern>repackaged.com</shadedPattern> <includes> <include>com.google.protobuf.**</include> <include>com.google.common.**</include> </includes> </relocation>
Créer un uber JAR ombré avec SBT
SBT
est un outil permettant de créer des applications Scala. Pour créer un fichier JAR ombré avec SBT, ajoutez le plug-in
sbt-assembly
à la description de votre build, en commençant par créer un fichier nommé assembly.sbt dans le répertoire project/ :
├── src/
└── build.sbt
└── project/
└── assembly.sbt
... puis en ajoutant la ligne suivante dans assembly.sbt :
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")Vous trouverez ci-dessous un exemple de fichier de configuration build.sbt qui effectue un ombrage sur la bibliothèque Guava, située dans le package com.google.common package.
lazy val commonSettings = Seq( organization := "YOUR_GROUP_ID", name := "YOUR_ARTIFACT_ID", version := "YOUR_PACKAGE_VERSION", scalaVersion := "YOUR_SCALA_VERSION", ) lazy val shaded = (project in file(".")) .settings(commonSettings) mainClass in (Compile, packageBin) := Some("YOUR_APPLICATION_MAIN_CLASS") libraryDependencies ++= Seq( "org.apache.spark" % "spark-sql_2.11" % "YOUR_SPARK_VERSION" % "provided", // YOUR_DEPENDENCIES ) assemblyShadeRules in assembly := Seq( ShadeRule.rename("com.google.common.**" -> "repackaged.com.google.common.@1").inAll )
Pour exécuter le build :
sbt assembly
Remarques sur build.sbt :
- La règle d'ombrage de l'exemple précédent est susceptible de ne pas résoudre tous les conflits de dépendance, car SBT utilise des stratégies de résolution de conflit strictes. Par conséquent, vous devrez peut-être fournir des règles plus détaillées permettant de fusionner explicitement des types de fichiers en conflit spécifiques à l'aide des stratégies
MergeStrategy.first,last,concat,filterDistinctLines,renameoudiscard. Pour en savoir plus, consultez la stratégie de fusion desbt-assembly. - Vous devrez peut-être ombrer plusieurs bibliothèques. Pour ce faire, incluez plusieurs chemins d'accès.
L'exemple suivant illustre l'ombrage des bibliothèques Guava et Protobuf :
assemblyShadeRules in assembly := Seq( ShadeRule.rename("com.google.common.**" -> "repackaged.com.google.common.@1").inAll, ShadeRule.rename("com.google.protobuf.**" -> "repackaged.com.google.protobuf.@1").inAll )
Envoyer l'uber JAR à Managed Service pour Apache Spark
Une fois que vous avez créé un fichier uber JAR ombré contenant votre application Spark
et ses dépendances, importez le fichier JAR dans Cloud Storage et envoyez une
tâche
à Managed Service pour Apache Spark (à l'aide de l'option --jars dans l'
interface de ligne de commande Google Cloud CLI, du champ Fichiers JAR de la Google Cloud console, du
champ jarFileUris de l'
API ou en spécifiant votre fichier JAR ombré comme fichier JAR d'application principal).
Étape suivante
- Consultez spark-translate, un exemple d'application Spark contenant des fichiers de configuration pour Maven et SBT.
- Apprenez à écrire et à exécuter des tâches Spark Scala sur un cluster Managed Service pour Apache Spark à l'aide du guide de démarrage rapide Managed Service pour Apache Spark Écrire et exécuter des tâches Spark Scala.