Criar e executar JARs na computação sem servidor

Importante

O Databricks recomenda fortemente os Pacotes de Automação Declarativa em vez de criar e implantar JARs manualmente, conforme descrito nesta página. Os Pacotes de Automação Declarativa facilitam a criação de um projeto a partir de um modelo que tenha as versões corretas do Scala, JDK e Databricks Connect já configuradas para sem servidor e também permite a implantação simples do JAR no workspace do Databricks. Consulte Criar um JAR Scala com pacotes de automação declarativa.

Um ARQUIVO JAVA (JAR) empacota código Java ou Scala em um único arquivo. Crie um JAR com código Spark e implante-o como uma tarefa JAR na computação sem servidor em um trabalho do Lakeflow.

Requirements

Para criar um JAR, seu ambiente de desenvolvimento local deve ter o seguinte instalado:

Versões de dependências

Importante

Para executar em computação sem servidor sem falhas, as versões do JAR, do Scala e do JDK devem corresponder exatamente às versões do Scala e do JDK do ambiente de execução. Consulte as versões do Databricks Connect.

O exemplo nesta página usa o ambiente sem servidor versão 4, portanto, esta página cria um JAR que:

  • É compilado para Scala 2.13; cada dependência usa o sufixo _2.13.
  • É compilado com base no JDK 17, versão do arquivo de classe 61.
  • É compilado no Databricks Connect 17.3, a superfície da API do Spark para computação sem servidor.
  • Usa somente APIs públicas do Spark. Ele não usa RDDs nem recursos internos do Spark. Confira Limitações.
  • Inclui todas as dependências no JAR ou anexadas como uma biblioteca de ambiente sem servidor. Consulte Gerenciamento de dependências.

Limitações

A computação sem servidor usa o Spark Connect. Seu JAR é executado com uma biblioteca de cliente leve que expõe as APIs públicas do Spark, enquanto o mecanismo do Spark é executado no lado do servidor. O código que ignora a API pública não pode se beneficiar da otimização do Catalyst ou da aceleração do Photon , mesmo na computação clássica. O código baseado em RDD e dependente interno geralmente é mais lento do que o dataframe ou código SQL equivalente.

As seguintes opções não estão disponíveis:

  • API RDD (org.apache.spark.rdd.*) e SparkContext / JavaSparkContext. Em vez disso, use SparkSession.builder().getOrCreate() e as operações de DataFrame/Dataset.
  • APIs internas do Spark (org.apache.spark.catalyst.*, , org.apache.spark.util.*org.apache.spark.sql.util.*, ). org.apache.spark.sql.internal.* O código que importa essas APIs falha com NoClassDefFoundError. Refatorar para a API pública do Spark. Se uma biblioteca de terceiros usa APIs internas, verifique se ela disponibiliza uma versão compatível com o Spark Connect.
  • Bibliotecas nativas (.so, .dll, JNI). A computação sem servidor não permite gravar bibliotecas nativas no sistema de arquivos. Bibliotecas que desempacotam binários nativos na inicialização falham com UnsatisfiedLinkError. Scripts de inicialização não são uma solução alternativa. Use um Java equivalente se estiver disponível.

Se a carga de trabalho exigir qualquer uma das opções acima, execute-a na computação padrão ou dedicada .

Etapa 1: Criar um JAR

Scala

  1. Execute o seguinte comando para criar um projeto Scala:

    sbt new scala/scala-seed.g8
    

    Quando solicitado, insira um nome de projeto, por exemplo, my-spark-app.

  2. Em seguida, exclua os arquivos stub da semente e crie o diretório para o seu código-fonte:

    cd my-spark-app
    rm src/main/scala/example/Hello.scala
    rm src/test/scala/example/HelloSpec.scala
    rm project/Dependencies.scala
    mkdir -p src/main/scala/com/examples
    
  3. Substitua o conteúdo do arquivo build.sbt pelo seguinte:

    name := "my-spark-app"
    
    // Set the dependency versions
    scalaVersion := "2.13.16"
    javacOptions ++= Seq("--release", "17")
    scalacOptions ++= Seq("-release", "17")
    
    libraryDependencies += "com.databricks" %% "databricks-connect" % "17.3.2" % "provided"
    // Your other dependencies go here. Use %% for Scala libraries so sbt picks the _2.13 artifact.
    
    // Fork a new JVM on run so our javaOptions are applied.
    fork := true
    javaOptions += "--add-opens=java.base/java.nio=ALL-UNNAMED"
    
  4. Edite ou crie um project/plugins.sbt arquivo e adicione esta linha:

    addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1")
    
  5. Crie sua classe principal em src/main/scala/com/examples/SparkJar.scala:

    package com.examples
    
    import org.apache.spark.sql.SparkSession
    
    object SparkJar {
      def main(args: Array[String]): Unit = {
        val spark = SparkSession.builder().getOrCreate()
    
        // Prints the arguments to the class, which
        // are job parameters when run as a job:
        println(args.mkString(", "))
    
        // Shows using spark:
        println(spark.version)
        println(spark.range(10).limit(3).collect().mkString(" "))
      }
    }
    
  6. Para criar seu arquivo JAR, execute o seguinte comando:

    sbt assembly
    

    O JAR compilado é criado na target/ pasta como my-spark-app-assembly-0.1.0-SNAPSHOT.jar.

Java

  1. Execute os seguintes comandos para criar uma estrutura de projeto do Maven:

    mkdir -p my-spark-app/src/main/java/com/examples
    cd my-spark-app
    
  2. Crie um pom.xml arquivo na raiz do projeto com o seguinte conteúdo:

    <?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>
    
      <groupId>com.examples</groupId>
      <artifactId>my-spark-app</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <properties>
        <maven.compiler.release>17</maven.compiler.release>
        <scala.binary.version>2.13</scala.binary.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      </properties>
    
      <dependencies>
        <!-- Included on serverless compute. -->
        <dependency>
          <groupId>com.databricks</groupId>
          <artifactId>databricks-connect_${scala.binary.version}</artifactId>
          <version>17.3.2</version>
          <scope>provided</scope>
        </dependency>
      </dependencies>
    
      <build>
        <plugins>
          <!-- Maven Shade Plugin - Creates a fat JAR with all non-provided dependencies. -->
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.6.1</version>
            <executions>
              <execution>
                <phase>package</phase>
                <goals>
                  <goal>shade</goal>
                </goals>
                <configuration>
                  <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                      <mainClass>com.examples.SparkJar</mainClass>
                    </transformer>
                  </transformers>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </project>
    
  3. Crie sua classe principal em src/main/java/com/examples/SparkJar.java:

    package com.examples;
    
    import org.apache.spark.sql.SparkSession;
    import java.util.stream.Collectors;
    
    public class SparkJar {
      public static void main(String[] args) {
        SparkSession spark = SparkSession.builder().getOrCreate();
    
        // Prints the arguments to the class, which
        // are job parameters when run as a job:
        System.out.println(String.join(", ", args));
    
        // Shows using spark:
        System.out.println(spark.version());
        System.out.println(
          spark.range(10).limit(3).collectAsList().stream()
            .map(Object::toString)
            .collect(Collectors.joining(" "))
        );
      }
    }
    
  4. Para criar seu arquivo JAR, execute o seguinte comando:

    mvn clean package
    

    O JAR compilado é criado na target/ pasta como my-spark-app-1.0-SNAPSHOT.jar.

Gerenciar dependências

Para disponibilizar uma biblioteca para seu JAR na computação sem servidor:

  • Use uma biblioteca fornecida: a computação sem servidor inclui o Databricks Connect e um conjunto de bibliotecas comuns. Se sua versão for compatível, declare-a provided em seu build e não a inclua em seu JAR.
  • Anexar como uma biblioteca de ambiente: adicione uma biblioteca ao seu ambiente sem servidor se ela ainda não for fornecida. Use isso para bibliotecas somente de runtime que você não deseja incluir.
  • Conecte-se a um banco de dados externo: para fontes JDBC, use uma conexão JDBC em vez de incluir um driver. As conexões JDBC são gerenciadas pelo Catálogo do Unity. Credenciais, linhagem e governança são gerenciadas para você.

Bibliotecas fornecidas

As bibliotecas a seguir são dependências necessárias e estão disponíveis por padrão na computação sem servidor. Declare-as provided em seu build. Incluir suas próprias versões dessas bibliotecas aciona um NoSuchMethodError em tempo de execução.

Note

As versões da biblioteca listadas abaixo são para o ambiente sem servidor versão 4. Para bibliotecas instaladas em outras versões do ambiente, consulte a referência notas de versão do ambiente sem servidor.

  • com.databricks:databricks-connect_2.13, versão 17.3.2
  • org.scala-lang:scala-library_2.13, versão 2.13.16
  • org.scala-lang:scala-reflect_2.13, versão 2.13.16
  • org.slf4j:slf4j-api, versão 2.0.10
  • org.apache.logging.log4j:log4j-api, versão 2.20.0
  • org.apache.logging.log4j:log4j-core, versão 2.20.0
  • org.apache.httpcomponents:httpclient, versão 4.5.14
  • org.apache.httpcomponents:httpcore, versão 4.4.16
  • com.fasterxml.jackson.core:jackson-databind, versão 2.15.2
  • com.fasterxml.jackson.core:jackson-core, versão 2.15.2
  • com.fasterxml.jackson.core:jackson-annotations, versão 2.15.2
  • com.fasterxml.jackson.datatype:jackson-datatype-jsr310, versão 2.15.2
  • com.google.guava:guava, versão 32.0.1-jre
  • commons-io:commons-io, versão 2.14.0
  • org.json4s:json4s-jackson_2.13, versão 4.0.7
  • org.apache.commons:commons-lang3, versão 3.14.0
  • org.apache.commons:commons-configuration2, versão 2.11.0
  • org.apache.commons:commons-text, versão 1.12.0
  • com.databricks:databricks-sdk-java, versão 0.52.0
  • com.databricks:databricks-dbutils-scala_2.13, versão 0.1.4

Etapa 2: Criar um trabalho para executar o JAR

  1. No seu espaço de trabalho, clique no ícone Fluxos de Trabalho.Tarefas e Pipelines na barra lateral.

  2. Clique em Criar e depois em Job.

  3. Clique no bloco JAR para configurar a primeira tarefa. Se o bloco JAR não estiver disponível, clique em Adicionar outro tipo de tarefa e pesquise jar.

  4. Opcionalmente, substitua o nome da tarefa, que usa New Job <date-time> como padrão, pelo nome da sua tarefa.

  5. No nome da tarefa, insira um nome para a tarefa, por exemplo JAR_example.

  6. Se necessário, selecione no menu suspenso JAR doTipo.

  7. Para a classe Main, insira o pacote e a classe do SEU JAR. Se você seguiu o exemplo anteriormente, insira com.examples.SparkJar.

  8. Para Computação, selecioneSem servidor.

  9. Configurar o ambiente sem servidor:

    1. Selecione um ambiente e clique no ícone Lápis.Edite para configurá-lo.
    2. Selecione 4 ou superior para a versão ambiente.
    3. Adicione seu arquivo JAR arrastando e soltando-o no seletor de arquivos ou navegue para escolhê-lo em um volume ou local de espaço de trabalho do Catálogo do Unity.
  10. Em Parâmetros, para este exemplo, insira ["Hello", "World!"].

  11. Clique em Salvar tarefa.

Etapa 3: Executar o trabalho e exibir os detalhes da execução do trabalho

Clique no Botão Executar agora para executar o fluxo de trabalho. Para exibir detalhes da execução, clique em Exibir execução no item pop-up da Execução disparada ou clique no link na coluna Hora de início da execução na exibição de execuções de trabalho.

Quando a execução for concluída, a saída será exibida no painel Saída , incluindo os argumentos passados para a tarefa.

Troubleshooting

A tabela a seguir fornece informações de solução de problemas para exceções comuns.

Exceção Cause Corrigir
NoSuchMethodError referenciando uma scala.* classe JAR compilado para Scala 2.12; o ambiente serverless executa Scala 2.13 Recompilar com scalaVersion := "2.13.16". Certifique-se de que cada dependência Scala use o sufixo de versão cruzada _2.13.
NoClassDefFoundError: scala/... Incompatibilidade entre Scala 2.12 e 2.13 Recompilar com scalaVersion := "2.13.16". Certifique-se de que cada dependência Scala use o sufixo de versão cruzada _2.13.
UnsupportedClassVersionError (uma versão de arquivo de classe superior a 61) Compilado com o JDK 18 ou superior; executa o JDK 17 sem servidor Usar <maven.compiler.release>17</maven.compiler.release> (Maven) ou --release 17 (sbt/javac)
NoClassDefFoundError: org/apache/spark/... para um pacote interno (catalyst, , util, sql/util, sql/internal, api/javaou rdd) A estrutura interna do Spark ou a API de RDD foi usada. Elas não estão disponíveis no serverless. Use a API pública do Spark (DataFrame/Dataset/SQL). Veja as limitações do serverless.
ClassNotFoundException para uma classe de driver JDBC (por exemplo, oracle.jdbc.OracleDriver) Driver JDBC não está no classpath Use uma conexão JDBC para o banco de dados externo.
ClassNotFoundException para uma classe de terceiros (por exemplo, kotlin.jvm.internal.*) A biblioteca não está no classpath sem servidor. Adicione-o ao SEU JAR ou forneça-o como um JAR adicional usando o ambiente sem servidor.
UnsatisfiedLinkError referenciando um arquivo em /tmp/ Biblioteca nativa incluída no JAR Bibliotecas nativas não são compatíveis com serverless. Use um equivalente Java puro ou seja executado na computação clássica.
NoSuchMethodError de uma biblioteca de terceiros (Apache Commons, Guava, Jackson, etc.) Sua versão incluída está em conflito com a versão fornecida pelo serverless. Use a versão fornecida. Marque-o provided em seu build e não inclua-o em seu JAR.

Próximas etapas