Mit Azure Batch lassen sich unter anderem umfangreiche, auf Parallelverarbeitung ausgelegte HPC-Batchaufträge (High Performance Computing) in Azure ausführen. Entwickler können so z. B. SaaS-Anwendungen oder Client-Apps erstellen, für die große Mengen von Ausführungen benötigt werden.
Vom Grundsatz her gestaltet sich die Arbeitsweise mit dem Plattform-Dienst so, dass Azure Batch vollkommen automatisch einen Pool mit Compute-Knoten (VMs) bereitstellt. Dort werden die gewünschten Anwendungen installiert und schließlich deren Ausführung als Aufträge auf den Compute-Knoten eingeplant.
Populäre Beispiele für den Einsatz von Batch-Processing sind Monte-Carlo-Risikosimulationen, die häufig von Finanzdienstleistern eingesetzt werden, oder allgemein das Erstellen von Diensten zur Verarbeitung großen Mengen von Bildern. Auch für so genannte eng gekoppelte Workloads wie FE-Analyse, Strömungssimulation oder das KI-Training mit mehreren Knoten eignet sich Azure Batch gut. Darüber hinaus unterstützt Azure Batch größere Mengen von Rendering-Workloads mit Rendering-Tools wie beispielsweise Autodesk Maya, 3ds Max oder V-Ray.
Haupteinsatzzweck ist aber sicher die Ausführung intrinsisch paralleler Workloads – also Anwendungen, die einerseits unabhängig voneinander ausgeführt werden, bei denen aber jede Instanz quasi nur einen Teil der Arbeit erledigt. Beliebte Beispiele für intrinsisch parallele Workloads, die sich mit Azure Batch ausführen lassen sind neben der bereits erwähnten Bildanalyse und -verarbeitung und der Modellierung von Finanzrisiken mit Monte Carlo-Simulationen, Medientranscodierung, die Datenerfassung-/Verarbeitung im Rahmen von ETL-Vorgängen, die Analyse genetischer Sequenzen, das Ausführen von Softwaretest oder die optische Zeichenerkennung (OCR). Letzte eignet sich im Rahmen dieses Beitrags gut für eine kurze Demo.
Grundlegende Konzepte von Azure Batch
Um erste Workloads mir Azure Batch erstellen zu können, ist ein grundlegendes Verständnis für die beteiligen Konzepte Batch-Konto, Knoten und Pools sowie Aufträge und Aufgaben vonnöten. Zunächst wird ein Azure-Batch-Konto benötigt. Darunter versteht Microsoft eine eindeutig identifizierbare Entität innerhalb des Batch-Diensts. Da die weitaus meisten Batch-Lösungen Azure Storage zur Speicherung von Ressourcen- und Ausgabedateien nutzen, ist jedem Azure Batch-Konto in der Regel ein entsprechenden Speicherkonto zugeordnet. Die Zuordnung kann bereits beim Anlegen des Batch-Account erfolgen. Pro Region ist es möglich, ein Batch-Konto anzulegen.
Wurde das Batch-Konto erstellt, können User im Abschnitt „Features / Pools“ die benötigten Pools und Knoten erstellen. Prinzipiell lassen sich durchaus mehrere Batch-Workloads in einem einzelnen Batch-Konto ausführen, falls gewünscht aber auch auf mehrere Batch-Konten verteilen, sofern sich diese im gleichen Abonnement (dann aber in verschiedenen Azure-Regionen) befinden.
Pools
Nun erstellen wir einen neuen Pool mit dem Namen „ocr-pool“, wählen bei „Imagetyp“ den Eintrag „Marketplace“ und als „Herausgeber“ den Eintrag „canonical“. Optional stehen als Images „debian“, „microsoftwindowsserver“ oder „microsoft-azure-batch“ zur Verfügung, aber für dieses Beispiel benötigen wir ein einfaches „Linux“-System. Als „Angebot“ nutzen wir daher „ubuntuserver“ und als SKU „18.04-lts“.
Im Abschnitt „Knotengröße“ legen wir zunächst die gewünschte VM-Größe fest. Dies verhält sich ähnlich wie beim Azure Kubernetes Service (AKS). Es handelt sich zwar im Prinzip um normale Azure-VMs, diese tauchen aber ausschließlich im Kontext von Azure Batch auf“. Im Normalfall empfiehlt sich bei Batch-Workloads ein Hardware-Typ, der besonders für HPC-Workloads geeignet ist, etwa ein System aus der F-Serie wie z. B. „Standard_f2s_v2“. Für unser einfaches Beispiel genügt aber auch ein System aus der A-, B- oder D-Serie für Allzweck-Workloads.
Verantwortlich für die letztlich erzielbare Performance ist nicht nur die Anzahl Kerne der gewählten Compute-Hardware, sondern auch die Anzahl der Konten im Pool. Dabei besteht die Wahl zwischen einer festen Größe des Pools und Autoscaling: Bei einer festen Knotenzahl sind drei Knoten sicherlich ein vernünftiger Ausgangspunkt; aus Kostengründen genügt für das Nachvollziehen dieser Demo auch ein Knoten.
Entscheidend für unser Beispiel ist aber, dass Sie im Abschnitt „Starttask“ einen Startsequenz angeben, die auf jedem einzelnen Compute-Knoten ausgeführt wird, sobald dieser dem Pool hinzugefügt oder wenn der Knoten neu gestartet wird. Da wir es hier mit Linux-Instanzen zu tun haben, dient für dieses Beispiel folgendes Bash-Skript als Starttask:
/bin/bash -c
„sudo update-locale LC_ALL=C.UTF-8 LANG=C.UTF-8; sudo apt-get update; sudo apt-get -y install ocrmypdf“
An der Installation des Linux-Paketes „ocrmypdf“ lässt sich erahnen, dass die später zu verwendende Azure-Function, die beim Upload eines scanntes Dokumentes in ein Speicherkonto, einen OCR-Vorgang anstoßen soll, das gleichnamige Open-Source-Tool verwenden wird. Alle übrigen Einstellungen verbleiben für dieses Beispiel auf den Default-Werten. Wurde der Pool erstellt, wird er mitsamt der zugewiesenen dedizierten Knotenzahl im Abschnitt „Pools“ des Batch-Accounts angezeigt.
Ist das erledigt, können wir im Abschnitt „Features / Aufträge“ einen Auftrag erstellen. Der benötigt erst einmal nur eine Auftrags-ID, z. B. „ocr-job“. Außerdem gilt es, den zu verwendenden Pool auszuwählen.
Speicherkonten und Azure Functions
Jetzt wechseln wir in das mit dem Batch-Account verknüpfte Speicherkonto und erstellen zwei Blob-Container mit dem Namen „input“ und „output“. Der Container „input“ dient dem Upload gescannter Dokumente und damit als Ereignis-Trigger für eine Azure-Function, die dann den ocr-Batch auslöst. Derweil dient „output“ als Ziel-Container für die per ORC analysierten Dokument. Wie man Container erstellt, haben wie Ihnen schon in verschiedenen Artikel gezeigt.
Für den sicheren anonymen Schreibzugriff auf den Ziel-Container „output“ erzeugen Sie noch eine SAS (Shared Access Signature), also eine signierte URL. Dies gelingt am einfachsten im Azure Storage Explorer. Durch einen Rechtsklick auf den gewünschten Container können Sie dann einfach den Eintrag „Shared Access Signature abrufen“ nutzen.
Sie benötigen die Berechtigung „Schreiben“ und einen gewünschten Bereich für die Dauer der SAS-Gültigkeit. Wurde die SAS abgerufen, kopieren Sie SAS-URL und Abfragezeichenfolge in die Zwischenablage, da Sie Diese später zum Autorisieren der Azure-Function benötigen.
Danach erstellen Sie im Azure-Portal eine neue Azure Function (Function App) mit serverlosen Verbrauchsplan. Wie das geht, haben wie bereits in verschiedenen Artikeln demonstriert (Link). Verwenden Sie diesmal .NET als Laufzeitstapel. Die für dieses Beispiel verwendete Function ist in C# geschrieben, um das Azure-Batch .NET SDK nutzen zu können. Wenn Sie den serverlosen Verbrauchsplan gewählt haben müssen Sie im Abschnitt „Hosting“ des Bereitstellungsassistenten das Speicherkonto angeben, das Sie oben erstellt und welches Sie mit der Azure Function verknüpfen möchten.
Wurde die Function-App erstellt, müssen Sie nur noch im Abschnitt „Funktionen“ einen neuen Trigger für Blob-Speicherkonten erstellen. Wählen Sie bei „Entwicklungseinstellungen“ den Eintrag „im Portal entwickeln“. Im Abschnitt „Vorlagendetails“ wählen Sie bei „neue Funktion“ einen beliebigen Namen für Ihren Trigger, und bei „Pfad“ ersetzen im Vorschlag „samples-workitems/{name}“ dem Eintrag „samples-workitems“ durch den Namen Ihres Eingangs-Containers, in unserem Beispiel „input“. Bei „Speicherkontoverbindung“ handelt es sich um den Namen der App-Einstellung, welche dann die Verbindungszeichenfolge für Ihr Speicherkonto enthält. Hier ist der Eintrag „AzureWebJobsStorage“ korrekt.