Os aplicativos Spark geralmente dependem de bibliotecas Java ou Scala de terceiros. Confira a seguir as abordagens recomendadas para incluir essas dependências ao enviar um job do Spark para um cluster do Serviço Gerenciado para Apache Spark:
Ao enviar um job da máquina local com o
gcloud dataproc jobs submitcomando, use a--properties spark.jars.packages=[DEPENDENCIES]flag.
Exemplo: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'
Ao enviar um job diretamente no cluster use o
spark-submitcomando com o--packages=[DEPENDENCIES]parâmetro.
Exemplo:spark-submit --packages='com.google.cloud:google-cloud-translate:1.35.0,org.apache.bahir:spark-streaming-pubsub_2.11:2.2.0'
Evitar conflitos de dependência
As abordagens anteriores podem falhar se as dependências do aplicativo Spark entrarem em conflito com as dependências do Hadoop. Esse conflito pode surgir porque o Hadoop injeta suas
dependências no
classpath do aplicativo,
de forma que as dependências dele têm precedência sobre as
dependências do aplicativo. Quando ocorre um conflito, NoSuchMethodError ou outros erros podem ser gerados.
Exemplo:
Guava
é a biblioteca principal do Google para Java que é usada por muitas bibliotecas e frameworks, incluindo o
Hadoop. Um conflito de dependência pode ocorrer se um job ou as dependências desse job exigirem uma versão do Guava que seja mais recente do que a utilizada pelo Hadoop.
O Hadoop v3.0 resolveu esse problema , mas os aplicativos que dependem de versões anteriores do Hadoop exigem a seguinte solução alternativa com duas partes para evitar possíveis conflitos de dependência.
- Crie um único JAR que contenha o pacote do aplicativo e todas as suas dependências.
- Realoque os pacotes de dependência conflitantes dentro do JAR uber para impedir que seus nomes de caminho conflitem com os dos pacotes de dependência do Hadoop. Em vez de modificar seu código, use um plug-in (veja abaixo) para executar automaticamente essa realocação (também conhecida como "sombreamento") como parte do processo de empacotamento.
Criar um JAR uber sombreado com o Maven
O Maven é uma ferramenta de gerenciamento de pacotes para a criação de aplicativos Java. O plug-in Maven scala pode ser usado para criar aplicativos escritos em Scala, a linguagem usada pelos aplicativos Spark. O plug-in de sombreamento do Maven pode ser usado para criar um JAR sombreado.
Este é um exemplo de arquivo de configuração pom.xml que sombreia a biblioteca Guava, localizada no pacote com.google.common. Essa configuração instrui o Maven a renomear o pacote com.google.common como repackaged.com.google.common e a atualizar todas as referências às classes do pacote original.
<?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>
Para executar a versão:
mvn package
Observações sobre pom.xml:
- ManifestResourceTransformer
processa atributos no arquivo de manifesto do JAR uber (
MANIFEST.MF). O manifesto também pode especificar o ponto de entrada para seu aplicativo. - O escopo do Spark
é
provided, já que ele está instalado no Serviço Gerenciado para Apache Spark. - Especifique a versão do Spark instalada no cluster do Serviço Gerenciado para Apache Spark (consulte a lista de versões do Serviço Gerenciado para Apache Spark). Se o aplicativo exigir uma versão do Spark diferente da versão instalada no cluster do Serviço Gerenciado para Apache Spark, escreva uma ação de inicialização ou crie uma imagem personalizada que instale a versão do Spark usada pelo aplicativo.
- A entrada
<filters>exclui arquivos de assinatura dos diretóriosMETA-INFdas dependências. Sem essa entrada, uma exceção de tempo de execuçãojava.lang.SecurityException: Invalid signature file digest for Manifest main attributespode ocorrer pelo fato dos arquivos de assinatura serem inválidos no contexto do JAR uber. - Pode ser necessário sombrear várias bibliotecas. Para fazer isso, inclua vários caminhos.
O exemplo a seguir sombreia as bibliotecas Guava e Protobuf.
<relocation> <pattern>com</pattern> <shadedPattern>repackaged.com</shadedPattern> <includes> <include>com.google.protobuf.**</include> <include>com.google.common.**</include> </includes> </relocation>
Criar um JAR uber sombreado com o SBT
SBT
é uma ferramenta para criar aplicativos Scala. Para criar um JAR sombreado com o SBT,
adicione o sbt-assembly
plug-in à sua definição de compilação, criando primeiro um arquivo chamado assembly.sbt
no diretório project/:
├── src/
└── build.sbt
└── project/
└── assembly.sbt
... adicionando a seguinte linha em assembly.sbt:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")Este é um exemplo de arquivo de configuração build.sbt que sombreia a biblioteca Guava, localizada no 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 )
Para executar a versão:
sbt assembly
Observações sobre build.sbt:
- A regra de sombreamento no exemplo anterior pode não resolver todos os conflitos de dependência, uma vez que o SBT usa estratégias restritas de resolução de conflitos. Portanto, talvez seja necessário fornecer regras mais granulares que mesclem explicitamente tipos específicos de arquivos conflitantes usando estratégias
MergeStrategy.first,last,concat,filterDistinctLines,renameoudiscard. Consulte a estratégia de mesclagem dosbt-assembly's para mais detalhes. - Pode ser necessário sombrear várias bibliotecas. Para fazer isso, inclua vários caminhos.
O exemplo a seguir sombreia as bibliotecas 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 )
Enviar o JAR uber para o Serviço Gerenciado para Apache Spark
Depois de criar um JAR uber sombreado que contenha os aplicativos do Spark e as respectivas dependências, estará tudo pronto para enviar um job ao Serviço Gerenciado para Apache Spark.
A seguir
- Consulte spark-translate, uma amostra do aplicativo Spark que contém arquivos de configuração para o Maven e para o SBT.
- Grave e execute jobs do Spark Scala no Serviço Gerenciado para Apache Spark. Guia de início rápido para aprender a escrever e executar jobs do Spark Scala em um cluster do Serviço Gerenciado para Apache Spark.