Administra las dependencias de Java y Scala para Apache Spark

Las aplicaciones de Spark a menudo dependen de bibliotecas de terceros de Java o Scala. Estos son los enfoques recomendados para incluir estas dependencias cuando envías un trabajo de Spark a un clúster de Cloud Dataproc:

  1. Cuando envíes un trabajo desde tu máquina local con el comando gcloud dataproc jobs submit, usa la marca --properties spark.jars.packages=[DEPENDENCIES].

    Ejemplo:

    gcloud dataproc jobs submit spark 
    --cluster my-cluster
    --properties spark.jars.packages='com.google.cloud:google-cloud-translate:1.35.0,org.apache.bahir:spark-streaming-pubsub_2.11:2.2.0'

  2. Cuando envíes un trabajo directamente en tu clúster, usa el comando spark-submit con el parámetro --packages=[DEPENDENCIES].

    Ejemplo:

    spark-submit --packages='com.google.cloud:google-cloud-translate:1.35.0,org.apache.bahir:spark-streaming-pubsub_2.11:2.2.0'
    

Evita conflictos de dependencias

Los enfoques anteriores pueden fallar si las dependencias de la aplicación de Spark entran en conflicto con las dependencias de Hadoop. Este conflicto puede surgir porque Hadoop inyecta sus dependencias en la ruta de clase de la aplicación, por lo que esas dependencias tienen prioridad sobre las de la aplicación. Cuando ocurre un conflicto, se pueden generar errores como NoSuchMethodError.

Ejemplo:
Guava es la biblioteca principal de Google para Java que usan muchas bibliotecas y marcos de trabajo, incluido Hadoop. Puede ocurrir un conflicto de dependencias si un trabajo o sus dependencias requieren una versión de Guava más nueva que la que usa Hadoop.

Hadoop v3.0 resolvió este problema, pero las aplicaciones que se basan en versiones anteriores de Hadoop requieren la siguiente solución de dos partes para evitar posibles conflictos de dependencias.

  1. Crear un solo JAR “uber” (también conocido como JAR “fat”) que contenga el paquete de la aplicación y todas sus dependencias
  2. Reubicar los paquetes de dependencia en conflicto dentro del JAR uber para evitar que sus nombres de ruta de acceso entren en conflicto con los de los paquetes de dependencia de Hadoop. En lugar de modificar tu código, usa un complemento (se detalla a continuación) para realizar de forma automática esta reubicación (también conocida como “shading”) como parte del proceso de empaquetado

Crea un JAR uber con shading mediante Maven

Maven es una herramienta de administración de paquetes para crear aplicaciones de Java. El complemento Maven scala se puede usar para crear aplicaciones escritas en Scala, el lenguaje que usan las aplicaciones de Spark. El complemento de Maven shade se puede usar para crear un JAR con shading.

El siguiente es un ejemplo de archivo de configuración pom.xml que aplica shading en la biblioteca de Guava, que se encuentra en el paquete com.google.common. Esta configuración le indica a Maven que cambie el nombre del paquete com.google.common a repackaged.com.google.common y que actualice todas las referencias a las clases del paquete 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>
              </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>

Usa el siguiente comando para ejecutar la compilación:

mvn package

Notas sobre pom.xml:

  • ManifestResourceTransformer procesa los atributos en el archivo de manifiesto del JAR uber (MANIFEST.MF). El manifiesto también puede especificar el punto de entrada para tu aplicación.
  • El alcance de Spark es provided, ya que Spark se instala en Cloud Dataproc.
  • Especifica la versión de Spark que se instala en tu clúster de Cloud Dataproc (consulta la Lista de versiones de Cloud Dataproc). Si tu aplicación requiere una versión de Spark diferente de la que está instalada en tu clúster de Cloud Dataproc, puedes escribir una acción de inicialización o construir una imagen personalizada que instale la versión de Spark que usa tu aplicación.
  • La entrada <filters> excluye los archivos de firma de los directorios META-INF de tus dependencias. Sin esta entrada, puede ocurrir una excepción de tiempo de ejecución java.lang.SecurityException: Invalid signature file digest for Manifest main attributes porque los archivos de firma no son válidos en el contexto de tu JAR uber.
  • Es posible que debas aplicar shading en varias bibliotecas. Para ello, debes incluir múltiples rutas de acceso. En el siguiente ejemplo, se aplica shading en las bibliotecas de Guava y Protobuf.
    <relocation>
      <pattern>com</pattern>
      <shadedPattern>repackaged.com</shadedPattern>
      <includes>
        <include>com.google.protobuf.**</include>
        <include>com.google.common.**</include>
      </includes>
    </relocation>
    

Crea un JAR uber con shading mediante SBT

SBT es una herramienta para compilar aplicaciones de Scala. Si deseas crear un JAR con shading mediante SBT, agrega el complemento sbt-assembly a tu definición de compilación, para lo cual primero debes crear un archivo llamado assembly.sbt dentro del directorio project/:

├── src/
└── build.sbt
└── project/
    └── assembly.sbt

… y, luego, debes agregar la siguiente línea en assembly.sbt:

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")

A continuación, se muestra un ejemplo de archivo de configuración build.sbt que aplica shading en la biblioteca de Guava, que se encuentra en 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
)

Usa el siguiente comando para ejecutar la compilación:

sbt assembly

Notas sobre build.sbt:

  • Es posible que la regla de shading del ejemplo anterior no resuelva todos los conflictos de dependencias porque SBT usa estrategias de resolución de conflictos estrictas. Por lo tanto, quizás debas proporcionar reglas más detalladas que fusionen de forma explícita tipos específicos de archivos en conflicto mediante las estrategias MergeStrategy.first, last, concat, filterDistinctLines, rename o discard. Consulta la estrategia de fusión de sbt-assembly para obtener más información.
  • Es posible que debas aplicar shading en varias bibliotecas. Para ello, debes incluir múltiples rutas de acceso. En el siguiente ejemplo, se aplica shading en las bibliotecas de Guava y 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
    )
    

Envía el JAR uber a Cloud Dataproc

Después de crear un JAR uber con shading que contenga tus aplicaciones de Spark y sus dependencias, puedes enviar un trabajo a Cloud Dataproc.

Pasos siguientes

  • Consulta spark-translate, una aplicación de ejemplo de Spark que contiene archivos de configuración para Maven y SBT.
  • Escribe y ejecuta trabajos Scala de Spark en Cloud Dataproc. Guía de inicio rápido para aprender a escribir y ejecutar trabajos Scala de Spark en un clúster de Cloud Dataproc.
¿Te sirvió esta página? Envíanos tu opinión:

Enviar comentarios sobre…

Documentación de Cloud Dataproc
¿Necesitas ayuda? Visita nuestra página de asistencia.