Condividi tramite


Usare un file JAR in un processo di Azure Databricks

L'archivio Java o formato di file JAR si basa sul noto formato di file ZIP e viene usato per aggregare molti file Java o Scala in un unico file. Usando l'attività JAR, è possibile garantire un'installazione rapida e affidabile del codice Java o Scala nei processi di Azure Databricks. Questo articolo fornisce un esempio di creazione di un file JAR e di un processo che esegue l'applicazione in pacchetto nel file JAR. Nel seguente esempio, si eseguirà quanto segue:

  • Creare il progetto JAR che definisce un'applicazione di esempio.
  • Aggregare i file di esempio in un file JAR.
  • Per eseguire il file JAR creare un processo.
  • Eseguire il processo e visualizzare i risultati.

Prima di iniziare

Per completare questo esempio, è necessario quanto segue:

  • Per Java JAR, Java Development Kit (JDK).
  • Per i JAR Scala, JDK e sbt.

Passaggio 1: Creare una directory locale per l'esempio

Creare una directory locale per contenere il codice di esempio e gli artefatti generati, ad esempio databricks_jar_test.

Passaggio 2: Creare il JAR

Completare le istruzioni seguenti per usare Java o Scala per creare il file JAR.

Creare un Java JAR

  1. Nella cartella databricks_jar_test creare un file denominato PrintArgs.java con il seguente contenuto:

    import java.util.Arrays;
    
    public class PrintArgs {
      public static void main(String[] args) {
        System.out.println(Arrays.toString(args));
      }
    }
    
  2. Compilare il file PrintArgs.java, che crea il file PrintArgs.class:

    javac PrintArgs.java
    
  3. (Facoltativo) Eseguire il programma compilato:

    java PrintArgs Hello World!
    
    # [Hello, World!]
    
  4. Nella stessa cartella dei file PrintArgs.java e PrintArgs.class creare una cartella denominata META-INF.

  5. Nella cartella META-INF creare un file denominato MANIFEST.MF con il seguente contenuto. Assicurarsi di aggiungere una nuova riga alla fine di questo file:

    Main-Class: PrintArgs
    
  6. Dalla radice della cartella databricks_jar_test creare un file JAR denominato PrintArgs.jar:

    jar cvfm PrintArgs.jar META-INF/MANIFEST.MF *.class
    
  7. (Facoltativo) Per testarlo, dalla radice della cartella databricks_jar_test, eseguire il file JAR:

    java -jar PrintArgs.jar Hello World!
    
    # [Hello, World!]
    

    Nota

    In caso di get l'errore no main manifest attribute, in PrintArgs.jar, assicurati di aggiungere una nuova riga alla fine del file MANIFEST.MF e quindi prova a creare ed eseguire nuovamente il file JAR.

  8. Caricare PrintArgs.jar in un volume. Vedere Caricare file in un volume Catalog Unity.

Creare un file JAR Scala

  1. Nella cartella databricks_jar_test creare un file vuoto denominato build.sbt con il seguente contenuto:

    ThisBuild / scalaVersion := "2.12.14"
    ThisBuild / organization := "com.example"
    
    lazy val PrintArgs = (project in file("."))
      .settings(
        name := "PrintArgs"
      )
    
  2. databricks_jar_test Dalla cartella creare la struttura src/main/scala/exampledi cartelle .

  3. Nella cartella example creare un file denominato PrintArgs.scala con il seguente contenuto:

    package example
    
    object PrintArgs {
      def main(args: Array[String]): Unit = {
        println(args.mkString(", "))
      }
    }
    
  4. Compilare il programma:

    sbt compile
    
  5. (Facoltativo) Eseguire il programma compilato:

    sbt "run Hello World\!"
    
    # Hello, World!
    
  6. Nella cartella databricks_jar_test/project creare un file denominato assembly.sbt con il seguente contenuto:

    addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.0.0")
    
  7. Dalla radice della cartella databricks_jar_test eseguire il comando assembly, che genera un file JAR nella cartella target:

    sbt assembly
    
  8. (Facoltativo) Per testarlo, dalla radice della cartella databricks_jar_test, eseguire il file JAR:

    java -jar target/scala-2.12/PrintArgs-assembly-0.1.0-SNAPSHOT.jar Hello World!
    
    # Hello, World!
    
  9. Caricare PrintArgs-assembly-0.1.0-SNAPSHOT.jar in un volume. Vedere Caricare file in un volume Catalog Unity.

Passaggio 3. Creare un processo di Azure Databricks per eseguire il file JAR

  1. Passare alla pagina di destinazione di Azure Databricks ed eseguire una delle operazioni seguenti:
    • Nella barra laterale, fare clic su Icona Flussi di lavoroFlussi di lavoro e quindi Pulsante Crea processo.
    • Nella barra laterale fare clic su Nuova iconaNuovo e select processo dal menu.
  2. Nella finestra di dialogo delle attività visualizzata nella scheda Attività sostituire Aggiungi un nome per il processo... con il nome del processo, ad esempio JAR example.
  3. Per Nome attività immettere un nome per l'attività, ad esempio java_jar_task per Java o scala_jar_task per Scala.
  4. Per Tipo, selectJAR.
  5. Per Classe principale, per questo esempio, immettere PrintArgs per Java o example.PrintArgs per Scala.
  6. Per il cluster , il cluster select è compatibile. Vedere Supporto per le librerie Java e Scala.
  7. Per Librerie dipendenti fare clic su + Aggiungi.
  8. Nella finestra di dialogo Aggiungi libreria dipendente, con Volumes selezionata, immettere il percorso where caricato il file JAR (PrintArgs.jar o PrintArgs-assembly-0.1.0-SNAPSHOT.jar) nel passaggio precedente in Volumes Percorso fileo filtrare o cercare il file JAR. Select.
  9. Fare clic su Aggiungi.
  10. Per Parameters, in questo esempio immettere ["Hello", "World!"].
  11. Fare clic su Aggiungi.

Passaggio 4: Eseguire il processo e visualizzare i dettagli dell'esecuzione del processo

Fare clic su Pulsante Esegui ora per eseguire il flusso di lavoro. Per visualizzare i dettagli per l'esecuzione, fare clic su Visualizza esecuzione nella finestra popup Esecuzione attivata o fare clic sul collegamento nella ora di inizio per l'esecuzione nella visualizzazione processo di .

Al termine dell'esecuzione, l'output viene visualizzato nel pannello Output, inclusi gli argomenti passati all'attività.

Limiti delle dimensioni di output per i processi JAR

L'output del processo, ad esempio l'output del log generato in stdout, è soggetto a una dimensione di 20 MB limit. Se l'output totale ha dimensioni maggiori, l'esecuzione viene annullata e contrassegnata come non riuscita.

Per evitare di riscontrare questo limit, è possibile impedire che stdout venga restituito dal driver ad Azure Databricks impostando la configurazione di spark.databricks.driver.disableScalaOutput Spark su true. Per impostazione predefinita, il valore del flag è false. Il flag controlla l'output della cella per i processi JAR scala e i notebook Scala. Se il flag è abilitato, Spark non restituisce i risultati dell'esecuzione del processo al client. Il flag non influisce sui dati scritti nei file di log del cluster. Databricks consiglia di impostare questo flag solo per i cluster automatizzati per i processi JAR, perché disabilita i risultati del notebook.

Raccomandazione: usare la condivisione SparkContext

Poiché Azure Databricks è un servizio gestito, potrebbero essere necessarie alcune modifiche al codice per garantire che i processi Apache Spark vengano eseguiti correttamente. I programmi di processo JAR devono usare l'API di SparkContext condivisa per get il SparkContext. Poiché Azure Databricks inizializza SparkContext, i programmi che richiamano new SparkContext() avranno esito negativo. Per get il SparkContext, usare solo i SparkContext condivisi creati da Azure Databricks:

val goodSparkContext = SparkContext.getOrCreate()
val goodSparkSession = SparkSession.builder().getOrCreate()

Esistono anche diversi metodi da evitare quando si usa l'oggetto condiviso SparkContext.

  • Non chiamare SparkContext.stop().
  • Non chiamare System.exit(0) o sc.stop() alla fine del programma Main. Ciò potrebbe causare comportamenti inaspettati.

Raccomandazione: usare i blocchi try-finally per la pulizia del processo

Si consideri un file JAR costituito da due parti:

  • jobBody() che contiene la parte principale del processo.
  • jobCleanup() che deve essere eseguito dopo jobBody(), indipendentemente dal fatto che tale funzione abbia avuto esito positivo o restituito un'eccezione.

Ad esempio, jobBody() crea tables e jobCleanup() elimina tali tables.

Il modo sicuro per assicurarsi che venga chiamato il metodo di pulizia consiste nell'inserire un blocco try-finally nel codice:

try {
  jobBody()
} finally {
  jobCleanup()
}

Non è consigliabile provare a eseguire la pulizia usando sys.addShutdownHook(jobCleanup) o il codice seguente:

val cleanupThread = new Thread { override def run = jobCleanup() }
Runtime.getRuntime.addShutdownHook(cleanupThread)

A causa del modo in cui la durata dei contenitori Spark viene gestita in Azure Databricks, gli hook di arresto non vengono eseguiti in modo affidabile.

Configurazione del processo JAR parameters

Passare parameters ai processi JAR con una matrice di stringhe JSON. Vedere l'oggetto spark_jar_task nel corpo della richiesta passato all'operazione Crea un nuovo processo (POST /jobs/create) nell'API Processi. Per accedere a questi parameters, esaminare l'array String passato nella funzione main.

Gestione delle dipendenze della libreria

Il driver Spark presenta alcune dipendenze della libreria che non possono essere sottoposte a override. Se il processo aggiunge librerie in conflitto, le dipendenze della libreria del driver Spark hanno la precedenza.

Per get il list completo delle dipendenze della libreria driver, eseguire il comando seguente in un notebook collegato a un cluster configurato con la stessa versione di Spark (o il cluster con il driver da esaminare):

%sh
ls /databricks/jars

Quando si definiscono le dipendenze della libreria per i file JAR, Databricks consiglia di elencare Spark e Hadoop come provided dipendenze. In Maven aggiungere Spark e Hadoop come dipendenze fornite:

<dependency>
  <groupId>org.apache.spark</groupId>
  <artifactId>spark-core_2.11</artifactId>
  <version>2.3.0</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>org.apache.hadoop</groupId>
  <artifactId>hadoop-core</artifactId>
  <version>1.2.1</version>
  <scope>provided</scope>
</dependency>

In sbt aggiungere Spark e Hadoop come dipendenze fornite:

libraryDependencies += "org.apache.spark" %% "spark-core" % "2.3.0" % "provided"
libraryDependencies += "org.apache.hadoop" %% "hadoop-core" % "1.2.1" % "provided"

Suggerimento

Specificare la versione di Scala corretta per le dipendenze in base alla versione in esecuzione.

Passaggi successivi

Per altre informazioni sulla creazione e l'esecuzione di processi di Azure Databricks, vedere Pianificare e orchestrare i flussi di lavoro.