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
Vorbemerkungen
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
Erstellen Sie im Ordner
databricks_jar_test
eine Datei mit dem NamenPrintArgs.java
und dem folgenden Inhalt:import java.util.Arrays; public class PrintArgs { public static void main(String[] args) { System.out.println(Arrays.toString(args)); } }
Kompilieren Sie die Datei
PrintArgs.java
, wodurch die DateiPrintArgs.class
erstellt wird:javac PrintArgs.java
(Optional) Führen Sie das kompilierte Programm aus:
java PrintArgs Hello World! # [Hello, World!]
Erstellen Sie im Ordner mit den Dateien
PrintArgs.java
undPrintArgs.class
einen Ordner namensMETA-INF
.Erstellen Sie im Ordner
META-INF
eine Datei mit dem NamenMANIFEST.MF
und dem folgenden Inhalt. Fügen Sie am Ende dieser Datei einen Zeilenumbruch hinzu:Main-Class: PrintArgs
Erstellen Sie im Stammverzeichnis des Ordners
databricks_jar_test
eine JAR-Datei mit dem NamenPrintArgs.jar
:jar cvfm PrintArgs.jar META-INF/MANIFEST.MF *.class
(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 DateiMANIFEST.MF
einen Zeilenumbruch ein. Versuchen Sie dann erneut, das JAR-Datei zu erstellen und auszuführen.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
Erstellen Sie im Ordner
databricks_jar_test
eine Datei mit dem Namenbuild.sbt
und dem folgenden Inhalt:ThisBuild / scalaVersion := "2.12.14" ThisBuild / organization := "com.example" lazy val PrintArgs = (project in file(".")) .settings( name := "PrintArgs" )
Erstellen Sie im Verzeichnis
databricks_jar_test
die Ordnerstruktursrc/main/scala/example
.Erstellen Sie im Ordner
example
eine Datei mit dem NamenPrintArgs.scala
und dem folgenden Inhalt:package example object PrintArgs { def main(args: Array[String]): Unit = { println(args.mkString(", ")) } }
Kompilieren Sie das Programm:
sbt compile
(Optional) Führen Sie das kompilierte Programm aus:
sbt "run Hello World\!" # Hello, World!
Erstellen Sie im Ordner
databricks_jar_test/project
eine Datei mit dem Namenassembly.sbt
und dem folgenden Inhalt:addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.0.0")
Führen Sie im Stammverzeichnis des
databricks_jar_test
-Ordners denassembly
-Befehl aus, der einen JAR unter demtarget
-Ordner generiert:sbt assembly
(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!
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
- Wechseln Sie zu Ihrer Azure Databricks-Zielseite, und führen Sie einen der folgenden Schritte aus:
- Klicken Sie in der Randleiste auf Workflows und dann auf .
- Klicken Sie auf der Randleiste auf Neu, und wählen Sie im Menü Auftrag aus.
- 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
. - Geben Sie als Aufgabenname einen Namen für die Aufgabe ein, z. B.
java_jar_task
für Java oderscala_jar_task
für Scala. - Wählen Sie für Typ die Option JAR aus.
- Geben Sie als Hauptklasse in diesem Beispiel
PrintArgs
für Java oderexample.PrintArgs
für Scala ein. - Wählen Sie für Cluster ein kompatibles Cluster aus. Weitere Informationen finden Sie unter Java- und Scala-Bibliotheksunterstützung.
- Klicken Sie unter Abhängige Bibliotheken auf + Hinzufügen.
- 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
oderPrintArgs-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. - Klicken Sie auf Hinzufügen.
- Geben Sie für Parameter in diesem Beispiel
["Hello", "World!"]
ein. - Klicken Sie auf Hinzufügen.
Schritt 4: Ausführen des Auftrags und Anzeigen von Details zur Auftragsausführung
Klicken Sie auf , 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)
odersc.stop()
nicht am Ende IhresMain
-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 nachjobBody()
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 Planen und Orchestrieren von Workflows..