Freigeben über


Verwenden einer JAR-Datei in einem Azure Databricks-Auftrag

Das Java-Archiv oder [JAR]-Dateiformat (https://en.wikipedia.org/wiki/JAR_(file_format)) basiert auf dem populären ZIP-Dateiformat und wird für die Zusammenfassung vieler Java- oder Scala-Dateien in einer Datei verwendet. Mithilfe der JAR-Aufgabe können Sie eine schnelle und zuverlässige Installation von Java- oder Scala-Code in Ihren Azure Databricks-Aufträgen sicherstellen. Dieser Artikel enthält ein Beispiel zum Erstellen einer JAR-Datei und eines Auftrags, der die in der JAR-Datei gepackte Anwendung ausführt. In diesem Beispiel führen Sie folgende Schritte aus:

  • Erstellen des JAR-Projekts, das eine Beispielanwendung definiert
  • Bündeln der Beispieldateien in einer JAR-Datei
  • Erstellen eines Auftrags zum Ausführen der JAR-Datei
  • Ausführen des Auftrags und Anzeigen der Ergebnisse

Voraussetzungen

Für dieses Beispiel benötigen Sie Folgendes:

  • Für Java-JAR-Dateien: das Java Development Kit (JDK)
  • Für Scala-JAR-Dateien: das JDK und sbt

Schritt 1: Erstellen eines lokalen Verzeichnisses für das Beispiel

Erstellen Sie ein lokales Verzeichnis, in dem Sie den Beispielcode und die generierten Artefakte (z. B. databricks_jar_test) speichern können.

Schritt 2: Erstellen der JAR-Datei

Führen Sie die folgenden Anweisungen aus, um die JAR-Datei mit Java oder Scala zu erstellen.

Erstellen einer Java-JAR-Datei

  1. Erstellen Sie im Ordner databricks_jar_test eine Datei mit dem Namen PrintArgs.java und dem folgenden Inhalt:

    import java.util.Arrays;
    
    public class PrintArgs {
      public static void main(String[] args) {
        System.out.println(Arrays.toString(args));
      }
    }
    
  2. Kompilieren Sie die Datei PrintArgs.java, wodurch die Datei PrintArgs.class erstellt wird:

    javac PrintArgs.java
    
  3. (Optional) Führen Sie das kompilierte Programm aus:

    java PrintArgs Hello World!
    
    # [Hello, World!]
    
  4. Erstellen Sie im Ordner mit den Dateien PrintArgs.java und PrintArgs.class einen Ordner namens META-INF.

  5. Erstellen Sie im Ordner META-INF eine Datei mit dem Namen MANIFEST.MF und dem folgenden Inhalt. Fügen Sie am Ende dieser Datei einen Zeilenumbruch hinzu:

    Main-Class: PrintArgs
    
  6. Erstellen Sie im Stammverzeichnis des Ordners databricks_jar_test eine JAR-Datei mit dem Namen PrintArgs.jar:

    jar cvfm PrintArgs.jar META-INF/MANIFEST.MF *.class
    
  7. (Optional) Führen Sie die JAR-Datei im Stammverzeichnis des Ordners databricks_jar_test aus, um sie zu testen:

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

    Hinweis

    Wenn Sie die Fehlermeldung no main manifest attribute, in PrintArgs.jar erhalten, fügen Sie am Ende der Datei MANIFEST.MF einen Zeilenumbruch ein. Versuchen Sie dann erneut, das JAR-Datei zu erstellen und auszuführen.

  8. Laden Sie PrintArgs.jar in ein Volume hoch. Weitere Informationen finden Sie unter Hochladen von Dateien auf ein Unity Catalog-Volume.

Erstellen einer Scala-JAR-Datei

  1. Erstellen Sie im Ordner databricks_jar_test eine Datei mit dem Namen build.sbt und dem folgenden Inhalt:

    ThisBuild / scalaVersion := "2.12.14"
    ThisBuild / organization := "com.example"
    
    lazy val PrintArgs = (project in file("."))
      .settings(
        name := "PrintArgs"
      )
    
  2. Erstellen Sie im Verzeichnis databricks_jar_test die Ordnerstruktur src/main/scala/example.

  3. Erstellen Sie im Ordner example eine Datei mit dem Namen PrintArgs.scala und dem folgenden Inhalt:

    package example
    
    object PrintArgs {
      def main(args: Array[String]): Unit = {
        println(args.mkString(", "))
      }
    }
    
  4. Kompilieren Sie das Programm:

    sbt compile
    
  5. (Optional) Führen Sie das kompilierte Programm aus:

    sbt "run Hello World\!"
    
    # Hello, World!
    
  6. Erstellen Sie im Ordner databricks_jar_test/project eine Datei mit dem Namen assembly.sbt und dem folgenden Inhalt:

    addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.0.0")
    
  7. Führen Sie im Stammverzeichnis des databricks_jar_test-Ordners den assembly-Befehl aus, der einen JAR unter dem target-Ordner generiert:

    sbt assembly
    
  8. (Optional) Führen Sie die JAR-Datei im Stammverzeichnis des Ordners databricks_jar_test aus, um sie zu testen:

    java -jar target/scala-2.12/PrintArgs-assembly-0.1.0-SNAPSHOT.jar Hello World!
    
    # Hello, World!
    
  9. Laden Sie PrintArgs-assembly-0.1.0-SNAPSHOT.jar in ein Volume hoch. Weitere Informationen finden Sie unter Hochladen von Dateien auf ein Unity Catalog-Volume.

Schritt 3. Erstellen eines Azure Databricks-Auftrags zum Ausführen der JAR-Datei

  1. Wechseln Sie zu Ihrer Azure Databricks-Zielseite, und führen Sie einen der folgenden Schritte aus:
    • Klicken Sie in der Randleiste auf Symbol für Workflows Workflows und dann auf Schaltfläche „Auftrag erstellen“.
    • Klicken Sie in der Randleiste auf Symbol „Neu“ Neu, und wählen Sie im Menü Auftrag aus.
  2. Ersetzen Sie im Aufgabendialogfeld, das auf der Registerkarte Aufgaben angezeigt wird, Namen für Ihren Auftrag hinzufügen… durch den Namen für den Auftrag, z. B. JAR example.
  3. Geben Sie als Aufgabenname einen Namen für die Aufgabe ein, z. B. java_jar_task für Java oder scala_jar_task für Scala.
  4. Wählen Sie für Typ die Option JAR aus.
  5. Geben Sie als Hauptklasse in diesem Beispiel PrintArgs für Java oder example.PrintArgs für Scala ein.
  6. Wählen Sie für Cluster ein kompatibles Cluster aus. Weitere Informationen finden Sie unter Java- und Scala-Bibliotheksunterstützung.
  7. Klicken Sie unter Abhängige Bibliotheken auf + Hinzufügen.
  8. Geben Sie im Dialogfeld Abhängige Bibliothek hinzufügen mit ausgewählter Option Volumes den Speicherort ein, in dem Sie die JAR-Datei (PrintArgs.jar oder PrintArgs-assembly-0.1.0-SNAPSHOT.jar) im vorherigen Schritt in den Volumesdateipfad hochgeladen haben. Filtern oder durchsuchen Sie alternativ das Dialogfeld, um die JAR-Datei zu finden. Wählen Sie ihn aus.
  9. Klicken Sie auf Hinzufügen.
  10. Geben Sie für Parameter in diesem Beispiel ["Hello", "World!"] ein.
  11. Klicken Sie auf Hinzufügen.

Schritt 4: Ausführen des Auftrags und Anzeigen von Details zur Auftragsausführung

Klicken Sie auf Schaltfläche „Jetzt ausführen“, um den Workflow auszuführen. Klicken Sie zum Anzeigen von Details zur Ausführung im Popupfenster Ausgelöste Ausführung auf Ausführung anzeigen, oder klicken Sie in der Ansicht Auftragsausführung auf den Link in der Spalte Startzeit für die Ausführung.

Nach Abschluss der Ausführung wird die Ausgabe im Bereich Ausgabe angezeigt, einschließlich der an die Aufgabe übergebenen Argumente.

Ausgabegrößenlimits für JAR-Aufträge

Die Auftragsausgabe, z. B. die an stdout ausgegebene Protokollausgabe, unterliegt einer Größenbeschränkung von 20 MB. Wenn die Gesamtausgabe diese Größe überschreitet, wird die Ausführung abgebrochen und als fehlgeschlagen markiert.

Um diesen Grenzwert nicht zu überschreiten, können Sie verhindern, dass stdout vom Treiber an Azure Databricks zurückgegeben wird. Dazu legen Sie in der Spark-Konfiguration spark.databricks.driver.disableScalaOutput auf den Wert true fest. Standardmäßig lautet der Flagwert false. Das Flag steuert die Zellenausgabe für Scala-JAR-Aufträge und Scala-Notebooks. Wenn das Flag aktiviert ist, gibt Spark keine Ergebnisse der Auftragsausführung an den Client zurück. Das Flag wirkt sich nicht auf die Daten aus, die in die Clusterprotokolldateien geschrieben werden. Databricks empfiehlt, dieses Flag nur für Auftrags-Cluster für JAR-Aufträge zu setzen, da es die Notebook-Ergebnisse deaktiviert.

Empfehlung: Verwenden Sie den freigegebenen SparkContext

Da Azure Databricks ein verwalteter Dienst ist, sind möglicherweise einige Codeänderungen erforderlich, um sicherzustellen, dass Ihre Apache Spark-Aufträge korrekt ausgeführt werden. JAR-Auftragsprogramme müssen die freigegebene SparkContext-API verwenden, um den SparkContext abzurufen. Da Azure Databricks den SparkContext initialisiert, kommt es bei Programmen, die new SparkContext() aufrufen, zu Fehlern. Verwenden Sie zum Abrufen von SparkContext nur den freigegebenen SparkContext, der von Azure Databricks erstellt wurde:

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

Es gibt außerdem einige Methoden, die Sie bei der Verwendung des freigegebenen SparkContext vermeiden sollten.

  • Rufen Sie nicht SparkContext.stop() auf.
  • Rufen Sie System.exit(0) oder sc.stop() nicht am Ende Ihres Main-Programms auf. Dies kann zu einem nicht definierten Verhalten führen.

Empfehlung: Verwenden Sie try-finally-Blöcke für die Auftragsbereinigung

Stellen Sie sich eine JAR vor, die aus zwei Teilen besteht:

  • jobBody() enthält den Hauptteil des Auftrags.
  • jobCleanup() muss nach jobBody() ausgeführt werden, unabhängig davon, ob diese Funktion erfolgreich war oder eine Ausnahme zurückgegeben hat.

jobBody() erstellt z. B. Tabellen und jobCleanup() löscht diese Tabellen.

Um sicherzustellen, dass die Aufräummethode aufgerufen wird, können Sie einen try-finally-Block in den Code einfügen:

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

Sie sollten nicht versuchen, eine Bereinigung mit sys.addShutdownHook(jobCleanup) oder dem folgenden Code durchzuführen:

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

Aufgrund der Art und Weise, wie die Lebensdauer von Spark-Containern in Azure Databricks verwaltet wird, werden die Hooks zum Herunterfahren nicht zuverlässig ausgeführt.

Konfigurieren von JAR-Auftragsparametern

Sie übergeben Parameter mit einem JSON-Zeichenfolgenarray an JAR-Aufträge. Sehen Sie sich das spark_jar_task-Objekt im Anforderungstext an, das an den Vorgang zum Erstellen eines neuen Auftrags (POST /jobs/create) in der Auftrags-API übergeben wird. Um auf diese Parameter zuzugreifen, untersuchen Sie das an Ihre main-Funktion übergebene String-Array.

Verwalten von Bibliotheksabhängigkeiten

Der Spark-Treiber verfügt über bestimmte Bibliotheksabhängigkeiten, die nicht überschrieben werden können. Wenn Ihr Auftrag konkurrierende Bibliotheken hinzufügt, haben die Abhängigkeiten der Spark-Treiberbibliothek Vorrang.

Um die vollständige Liste der Abhängigkeiten von Treiberbibliotheken zu erhalten, führen Sie den folgenden Befehl in einem Notebook aus, das mit einem Cluster verbunden ist, der mit der gleichen Spark-Version konfiguriert ist (oder dem Cluster mit dem Treiber, den Sie untersuchen möchten):

%sh
ls /databricks/jars

Wenn Sie Abhängigkeiten von Bibliotheken für JARs definieren, empfiehlt Databricks, Spark und Hadoop als provided-Abhängigkeiten aufzulisten. Fügen Sie in Maven Spark und Hadoop als bereitgestellte Abhängigkeiten hinzu:

<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>

Fügen Sie in sbt Spark und Hadoop als bereitgestellte Abhängigkeiten hinzu:

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

Tipp

Geben Sie basierend auf der von Ihnen verwendeten Version die richtige Scala-Version für Ihre Abhängigkeiten an.

Nächste Schritte

Weitere Informationen zum Erstellen und Ausführen von Azure Databricks-Aufträgen finden Sie unter Erstellen und Ausführen von Azure Databricks-Aufträgen.