Spark-Anwendungen sind häufig auf Java- oder Scala-Bibliotheken von Drittanbietern angewiesen. In diesem Artikel finden Sie empfohlene Vorgehensweisen zum Einbeziehen dieser Abhängigkeiten, wenn Sie einen Spark-Job an einen Managed Service for Apache Spark-Cluster senden:
Wenn Sie einen Auftrag von Ihrem lokalen Rechner mit dem Befehl
gcloud dataproc jobs submitsenden, verwenden Sie das Flag--properties spark.jars.packages=[DEPENDENCIES].
Beispiel: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'
Wenn Sie einen Job direkt im Cluster senden, verwenden Sie den Befehl
spark-submitmit dem Parameter--packages=[DEPENDENCIES].
Beispiel:spark-submit --packages='com.google.cloud:google-cloud-translate:1.35.0,org.apache.bahir:spark-streaming-pubsub_2.11:2.2.0'
Wenn Sie benutzerdefinierte JAR-Dateien oder Bundles einbinden:
- Jobspezifische Abhängigkeiten:Geben Sie den Cloud Storage-Pfad zu
Ihrem JAR mit dem Flag
--jars, dem Cloud de Confiance Konsolenfeld JAR-Dateien oder dem API-FeldjarFileUrisan, wenn Sie einen Job senden. - Clusterweite Abhängigkeiten:Verwenden Sie das
spark:spark.jars-Clusterattribut während der Clustererstellung (--properties="spark:spark.jars=gs://<var>your-bucket</var>/<var>your-jarfile</var>.jar").
- Jobspezifische Abhängigkeiten:Geben Sie den Cloud Storage-Pfad zu
Ihrem JAR mit dem Flag
Abhängigkeitskonflikte vermeiden
Die oben beschriebenen Vorgehensweisen können fehlschlagen, wenn Abhängigkeiten von Spark-Anwendungen mit Abhängigkeiten von Hadoop in Konflikt stehen. Ein solcher Konflikt kann entstehen, da Hadoop seine Abhängigkeiten in den Klassenpfad der Anwendung so einfügt, dass sie gegenüber den Abhängigkeiten der Anwendung Vorrang haben. Wenn ein Konflikt auftritt, können Fehler wie NoSuchMethodError ausgegeben werden.
Beispiel:
Guava ist die zentrale Google-Mediathek für Java, die von vielen Mediatheken und Frameworks, einschließlich Hadoop, verwendet wird. Ein Abhängigkeitskonflikt kann auftreten, wenn für einen Job oder dessen Abhängigkeiten eine Version von Guava erforderlich ist, die neuer als die von Hadoop verwendete ist.
Hadoop v3.0 behoben
dieses Problem behoben. Bei Anwendungen, die auf früheren Hadoop-Versionen basieren, ist allerdings der folgende zweiteilige Workaround erforderlich, um mögliche Abhängigkeitskonflikte zu vermeiden.
- Erstellen Sie eine einzelne JAR-Datei, die das Paket der Anwendung und alle zugehörigen Abhängigkeiten enthält.
- Verschieben Sie die in Konflikt stehenden Abhängigkeitspakete innerhalb der Uber-JAR-Datei. So wird verhindert, dass ihre Pfadnamen mit den Pfadnamen der Hadoop-Abhängigkeitspakete in Konflikt geraten. Statt hierfür Ihren Code zu ändern, verwenden Sie ein Plug-in (siehe unten), um diese Verschiebung (auch als "Shading" bezeichnet) automatisch im Rahmen der Paketerstellung durchzuführen.
Shading-Uber-JAR-Datei mit Maven erstellen
Maven ist ein Paketverwaltungstool zum Erstellen von Java-Anwendungen. Mit dem Maven-Scala-Plug-in können Anwendungen erstellt werden, die in Scala geschrieben sind, der von Spark-Anwendungen verwendeten Sprache. Maven-Shade
Plug-in kann dazu verwendet werden, eine Shading-JAR-Datei zu erstellen.
Das folgende Beispiel zeigt eine pom.xml-Konfigurationsdatei, die die Guava-Mediathek, die sich im Paket com.google.common befindet, schattiert. Diese Konfiguration weist Maven an, das Paket com.google.common in repackaged.com.google.common umzubenennen und alle Verweise auf die Klassen aus dem ursprünglichen Paket zu aktualisieren.
<?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>
So führen Sie den Build aus:
mvn package
Hinweise zu pom.xml:
- ManifestResourceTransformer verarbeitet Attribute in der Manifestdatei der Uber-JAR-Datei (
MANIFEST.MF). Das Manifest kann auch den Einstiegspunkt für Ihre Anwendung angeben. - Der Bereich von Spark ist
provided, da Spark in Managed Service for Apache Spark installiert ist. - Geben Sie die Version von Spark an, die in Ihrem Managed Service for Apache Spark-Cluster installiert ist. Informationen hierzu finden Sie in der Liste der Managed Service for Apache Spark-Versionen. Wenn für Ihre Anwendung eine andere Spark-Version als die in Ihrem Managed Service for Apache Spark-Cluster installierte Version erforderlich ist, können Sie eine Initialisierungsaktion schreiben oder ein benutzerdefiniertes Image erstellen, mit dem die von Ihrer Anwendung verwendete Spark-Version installiert wird.
- Der Eintrag
<filters>schließt Signaturdateien aus denMETA-INF-Verzeichnissen Ihrer Abhängigkeiten aus. Ohne diesen Eintrag kann einejava.lang.SecurityException: Invalid signature file digest for Manifest main attributes-Laufzeitausnahme auftreten, da die Signaturdateien im Kontext Ihrer Uber-JAR-Datei ungültig sind. - Es kann sein, dass mehrere Bibliotheken umbenannt werden müssen. Fügen Sie dazu mehrere Pfade ein.
Im nächsten Beispiel werden die Bibliotheken Guava und Protobuf umbenannt.
<relocation> <pattern>com</pattern> <shadedPattern>repackaged.com</shadedPattern> <includes> <include>com.google.protobuf.**</include> <include>com.google.common.**</include> </includes> </relocation>
Shading-Uber-JAR-Datei mit SBT erstellen
SBT ist ein Tool zum Erstellen von Scala-Anwendungen. Wenn Sie eine Shading-JAR-Datei mit SBT erstellen möchten, fügen Sie das Plug-in sbt-assembly
Fügen Sie der Build-Definition das Plug-in hinzu. Erstellen Sie dazu zuerst eine Datei mit dem Namen assembly.sbt im Verzeichnis project/:
├── src/
└── build.sbt
└── project/
└── assembly.sbt
... und fügen Sie dann die folgende Zeile in assembly.sbt hinzu:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")Das folgende Beispiel zeigt die Konfigurationsdatei build.sbt, mit der die Guava-Mediathek, die sich im com.google.common package befindet, umbenannt wird (Shading).
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 )
So führen Sie den Build aus:
sbt assembly
Hinweise zu build.sbt:
- Möglicherweise werden mit der Shading-Regel oben nicht alle Abhängigkeitskonflikte gelöst, da SBT ganz bestimmte Strategien zur Konfliktlösung verwendet. Daher kann es sein, dass Sie detailliertere Regeln angeben müssen, durch die bestimmte Arten von in Konflikt stehenden Dateien ausdrücklich zusammengeführt werden. Verwenden Sie hierbei die Strategie
MergeStrategy.first,last,concat,filterDistinctLines,renameoderdiscard. Weitere Informationen finden Sie in der Zusammenführungsstrategie vonsbt-assembly. - Es kann sein, dass mehrere Bibliotheken umbenannt werden müssen. Fügen Sie dazu mehrere Pfade ein.
Im nächsten Beispiel werden die Bibliotheken Guava und Protobuf umbenannt.
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 )
Uber-JAR an Managed Service for Apache Spark senden
Nachdem Sie eine Shading-Uber-JAR-Datei erstellt haben, die Ihre Spark-Anwendung und ihre Abhängigkeiten enthält, laden Sie die JAR-Datei in Cloud Storage hoch und senden Sie einen Job an Managed Service for Apache Spark. Verwenden Sie dazu das Flag --jars in der Google Cloud CLI, das Feld JAR-Dateien in der Cloud de Confiance Console, das API-Feld jarFileUris oder geben Sie Ihre Shading-JAR-Datei als Hauptanwendungs-JAR-Datei an.
Nächste Schritte
- Sehen Sie sich die Spark-Beispielanwendung spark-translate an, die Konfigurationsdateien für Maven und SBT enthält.
- Spark-Scala-Jobs in Managed Service for Apache Spark schreiben und ausführen – Kurzanleitung dazu, wie Spark-Scala-Jobs in einem Managed Service for Apache Spark-Cluster geschrieben und ausgeführt werden