Le applicazioni Spark spesso dipendono da librerie Java o Scala di terze parti. Di seguito sono riportati gli approcci consigliati per includere queste dipendenze quando invii un job Spark a un cluster Dataproc:
Quando invii un job dalla tua macchina locale con il comando
gcloud dataproc jobs submit
, utilizza il flag--properties spark.jars.packages=[DEPENDENCIES]
.
Esempio: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'
Quando di inviare un job direttamente sul cluster utilizza il comando
spark-submit
con il parametro--packages=[DEPENDENCIES]
.
Esempio:spark-submit --packages='com.google.cloud:google-cloud-translate:1.35.0,org.apache.bahir:spark-streaming-pubsub_2.11:2.2.0'
Evitare conflitti di dipendenza
Gli approcci precedenti potrebbero non riuscire se le dipendenze dell'applicazione Spark sono in conflitto con le dipendenze di Hadoop. Questo conflitto può verificarsi perché Hadoop inietta le proprie dipendenze nel classpath dell'applicazione, pertanto le sue dipendenze hanno la precedenza sulle dipendenze dell'applicazione. In caso di conflitto, NoSuchMethodError
o altri errori
possono essere generati.
Esempio:
Guava
è la libreria di base di Google per Java utilizzata da molti framework e librerie, tra cui
Hadoop. Un conflitto di dipendenze può verificarsi se un job o le sue dipendenze richiedono un
più recente di quella utilizzata da Hadoop.
Hadoop 3.0 ha risolto questo problema, ma le applicazioni che si basano su versioni precedenti di Hadoop richiedono la seguente soluzione alternativa in due parti per evitare possibili conflitti di dipendenza.
- Crea un singolo file JAR contenente il pacchetto dell'applicazione e tutte le sue dipendenze.
- Rilocazione dei pacchetti di dipendenze in conflitto all'interno dell'uber JAR per evitare che i nomi dei percorsi entrino in conflitto con quelli dei pacchetti di dipendenze di Hadoop. Anziché modificare il codice, utilizza un plug-in (vedi sotto) per visualizzare automaticamente il trasferimento (o "ombreggiatura") come parte del processo di confezionamento.
Creazione di un uber JAR ombreggiato con Maven
Maven è uno strumento di gestione dei pacchetti per la creazione di applicazioni Java. Plug-in Maven scala può essere utilizzato per creare applicazioni scritte in Scala, il linguaggio utilizzato da Spark diverse applicazioni. La tonalità Maven per creare un JAR ombreggiato.
Di seguito è riportato un file di configurazione pom.xml
di esempio che esegue l'oscuramento della libreria Guava, che si trova nel pacchetto com.google.common
. Questa configurazione
indica a Maven di rinominare il pacchetto com.google.common
in
repackaged.com.google.common
e per aggiornare tutti i riferimenti al
del pacchetto originale.
<?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>
Per eseguire la compilazione:
mvn package
Note su pom.xml
:
- ManifestResourceTransformer
elabora gli attributi nel file manifest di Uber JAR (
MANIFEST.MF
). Il file manifest può anche specificare il punto di ingresso per l'applicazione. - L'ambito di Spark è
provided
, poiché Spark è installato su Dataproc. - Specifica la versione di Spark installata sul tuo cluster Dataproc (vedi Elenco delle versioni di Dataproc). Se la tua applicazione richiede una versione di Spark diversa dalla versione installato sul tuo cluster Dataproc, puoi scrivere azione di inizializzazione o crea un'immagine personalizzata che installa la versione Spark utilizzata dalla tua applicazione.
- L'elemento
<filters>
esclude i file di firma dalle directoryMETA-INF
delle dipendenze. Senza questa voce, può verificarsi un'eccezione di runtimejava.lang.SecurityException: Invalid signature file digest for Manifest main attributes
perché i file di firma non sono validi nel contesto dell'uber JAR. - Potresti dover ombreggiare più librerie. Per farlo, includi più percorsi.
Il prossimo esempio ombreggia le librerie Guava e Protobuf.
<relocation> <pattern>com</pattern> <shadedPattern>repackaged.com</shadedPattern> <includes> <include>com.google.protobuf.**</include> <include>com.google.common.**</include> </includes> </relocation>
Creazione di un JAR uber ombreggiato con SBT
SBT
è uno strumento per la creazione di applicazioni Scala. Per creare un JAR ombreggiato con SBT:
aggiungi sbt-assembly
plug-in alla definizione della build, creando innanzitutto un file denominato assembly.sbt
nella directory project/
:
├── src/ └── build.sbt └── project/ └── assembly.sbt
... quindi aggiungendo la seguente riga in assembly.sbt
:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")
Di seguito è riportato un file di configurazione build.sbt
di esempio che esegue l'oscuramento della libreria Guava, che si trova in 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 )
Per eseguire la build:
sbt assembly
Note su build.sbt
:
- La regola di sfumatura nell'esempio riportato sopra potrebbe non risolvere tutti i conflitti di dipendenza perché SBT utilizza strategie di risoluzione dei conflitti rigorose. Pertanto,
potresti dover fornire regole più granulari che uniscono esplicitamente criteri
tipi di file in conflitto utilizzando
MergeStrategy.first
,last
,concat
, StrategiefilterDistinctLines
,rename
odiscard
. Scopri la strategia di unione disbt-assembly
per ulteriori dettagli. - Potrebbe essere necessario oscurare più librerie. Per farlo, includi più percorsi.
Il prossimo esempio ombreggia le librerie Guava e 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 )
Invio del JAR uber a Dataproc
Dopo aver creato un JAR uber ombreggiato contenente le tue applicazioni Spark e le sue dipendenze, è tutto pronto per inviare un job a Dataproc.
Passaggi successivi
- Consulta spark-translate, un'applicazione Spark di esempio che contiene file di configurazione sia per Maven che per SBT.
- Scrivere ed eseguire job Spark Scala su Dataproc. Guida rapida per imparare a scrivere ed eseguire job Spark Scala su un cluster Dataproc.