Blog Post

Ein Framework zur Automatisierung: Warum Airflow?

  • Expert:innen Marvin Taschenberger
  • Datum 06. Juli 2018
  • Thema Cloud TechnologyData Engineering
  • Format Blog
  • Kategorie Technology
Ein Framework zur Automatisierung: Warum Airflow?

Kürzlich standen wir bei STATWORX vor der typischen Situation, dass wir einen Proof of Concept (POC) in etwas umwandeln mussten, das in der Produktion verwendet werden konnte. Der „neue“ Aspekt dieser Umwandlung bestand darin, dass der PoC mit einer winzigen Menge (ein paar hundert Megabyte) geladen war, aber für eine riesige Datenmenge (Terabyte) vorbereitet werden musste. Der Schwerpunkt lag auf dem Aufbau von Datenpipelines, die alle Einzelteile miteinander verbinden und den gesamten Workflow von der Datenbank über ETL (Extract-Transform-Load) und Berechnungen bis hin zur eigentlichen Anwendung automatisieren. Das einfache Master-Skript, das ein Skript nach dem anderen aufruft, kam also nicht mehr in Frage. Es war relativ klar, dass ein Programm oder ein Framework, das DAG’s verwendet, notwendig war. Daher werde ich in diesem Beitrag kurz darauf eingehen, was eine DAG in diesem Zusammenhang ist, welche Alternativen wir in Betracht gezogen haben und für welche wir uns letztendlich entschieden haben. Außerdem gibt es einen zweiten Teil, in dem genauer erklärt wird, wie der Arbeitsablauf mit Airflow aussieht, z.B. ein Hallo-Welt-Programm und das ganze Setup.

Was ist eine DAG?

DAG ist das Akronym für Directed Acyclic Graph und ist ein mathematisches Konzept, um Knoten in Beziehung zueinander darzustellen, allerdings ohne dabei Zyklen zu erlauben. Mit anderen Worten, es handelt sich einfach um einen Haufen von Knoten, die miteinander verbunden sind (linker Teil des Bildes unten). Als nächstes fügen wir Beziehungen zwischen den einzelnen Knoten hinzu (mittlerer Teil des Bildes unten), die in immer nur in eine bestimmte Richtung weisen dürfen, und schließlich beschränken wir die Verbindungen so, dass sie keine Zyklen zwischen den Knoten bilden (rechter Teil des Bildes unten).

In der Programmierung kann diese spezielle From eines Ausführungsplans verwendet werden, um alle notwendigen Prozessschritte als einen Knoten im Graphen zu definieren. Jede Aufgabe, die selbständig erledigt werden kann, ist ein Anfangsknoten ohne Vorgänger und hat als solcher keine abhängingen, vorgeschalteten Beziehungspunkte. Ausgehend von einem Anfangsknoten werden wir die Aufgaben verknüpfen, die direkt von diesem abhängig sind. Wenn wir diesen Prozess fortsetzen und alle Aufgaben mit dem daraus entstehenden Graphen verbinden, können wir ein ganzes Projekt in einem visuellen Ablaufplan darstellen. Auch wenn dies für einfache Projekte wie „führe erst A aus, dann B und schließlich C“ trivial sein mag, ist dies ab einer gewissen Größe oder Komplexität des Workflows nicht mehr der Fall. Komplexe Arbeitsabläufe, mit mehreren Aufgaben, die wiederum direkte und indirekte Abhängigkeiten aufweisen können, bietet das ideale Szenario die Stärken der DAG-Darstellung auszunutzen. Ein DAG gibt daher nicht nur einen nützlichen Einblick, wie sich Abhängigkeiten auf die eigentlich Ausführung des Prozesses auswirken (welche Aufgben dürfen parallel, welche müssen sequentiell ausgeführt werden). Sondern ist als visuelle Darstellung hilfreich, um diesen Prozess auch für Nicht-Experten leicht verständlich zu machen.

Stellen Sie sich vor, Sie haben einen Arbeitsablauf, der aus mehreren Dutzend Aufgaben besteht (wie die obige), von denen einige sequentiell und andere parallel ablaufen müssen. Stellen Sie sich vor, eine dieser Aufgaben würde fehlschlagen – ohne den DAG wäre nicht klar, was als nächstes geschehen soll. Welche Aufgabe muss warten, bis die fehlgeschlagene Aufgabe endlich erfolgreich ist? Welche kann weiterlaufen, da sie nicht von ihr abhängt? Mit einer DAG kann diese Frage schnell beantwortet werden und stellt sich für den Anwender nicht einmal dann, wenn ein Programm den Überblick darüber behält. Aufgrund dieser Bequemlichkeit haben viele Programme und Pakete diese Darstellung übernommen, um Arbeitsabläufe zu automatisieren.

Wonach haben wir gesucht?

Wie bereits erwähnt, waren wir auf der Suche nach einer Software, einem Framework oder zumindest einer Bibliothek als Orchestrator, die auf der Basis von DAGs arbeitet, den Überblick über die gesamten Workflows behält und mit eventuell auftretenden Fehlern (z.B. eine Aufgabe schlägt fehlt) umgehen kann. Darüber hinaus wäre ein eingebauter, „advanced“ Scheduler vorteilhaft, da der Ablauf jede Woche ausgeführt werden muss und eine manuelle Überwachung daher sehr mühsam wäre. Warum advanced? – Es gibt einfache Scheduler wie cron, die sich hervorragend eignen, um einen bestimmten Job zu einer bestimmten Zeit zu starten, die sich aber nicht, oder nur sehr aufwendig in den Workflow nativ integrieren lassen. Ein Scheduler, der auch die DAGs (mit allen Abhängigkeiten und Besonderheiten) im Auge behält, wäre also großartig. Schließlich sollte neben der leichten Erweiterbarkeit des Workflows dieser auch skalierbar sein. Es wäre also hilfreich, wenn wir ein Skript, z. B. zum Bereinigen von Daten, mehrmals nur mit einem anderen Argument (für verschiedene Datenstapel) als verschiedene Knoten im Workflow ohne viel Overhead und Code aufrufen könnten.

Was waren unsere Optionen?

Nachdem wir die Entscheidung getroffen hatten, dass wir einen DAG basierten Orchestrator implementieren müssen, tauchten in der anschließenden Google-Suche eine Vielzahl von Software, Frameworks und Paketen auf. Es war notwendig, die Menge der Optionen einzugrenzen, so dass nur einige wenige übrig blieben, die wir eingehend untersuchen konnten. Auch stellten wir fest, dass wir ein Tool brauchen, das nicht nur überwiegend GUI basiert ist, da dies die Flexibilität und Skalierbarkeit einschränkt. Es sollte allerdings auch nicht zu code-intensiv oder in einer unbequemen Programmiersprache sein, da die daraus resuliteriende, flache Lernkurve eine rasche Adaption verhindert und es zusätzlich länger dauert alle Projekt Stakeholder an Bord zu holen. Daher wurden Optionen wie Jenkins oder WAF sofort verworfen. Dennoch konnten wir die Auswahl auf drei Optionen eingrenzen.

Option 1 – Native Lösung: Cloud-Orchestrator

Da der PoC in einer Cloud bereitgestellt wurde, war die erste Option auch ziemlich offensichtlich – wir könnten einen der nativen Orchestratoren verwenden. Diese böten uns eine einfache GUI zur Definition unserer DAGs, einen Scheduler und waren darauf ausgelegt, Daten wie in unserem Fall notwendig zu routen. Auch wenn sich das gut anhört, war das unvermeidliche Problem, dass solche GUIs die oben genannte Flexibilität einschränken, man für die Benutzung natürlich bezahlen müsste und es ohne Coden überhaupt keinen Spaß machen würde. Trotzdem behielten wir die Lösung als Backup-Plan bei.

Option 2 – Apaches Hadoop-Lösungen: Oozie oder Askaban

Oozie und Azkaban sind beides Open-Source Workflow-Manager, die in Java geschrieben und für die Integration in Hadoop-Systeme konzipiert sind. Sie sind daher beide für die Ausführung von DAGs entworfen, skalierbar und haben einen integrierten Scheduler. Während Oozie versucht, hohe Flexibilität im Tausch gegen Benutzerfreundlichkeit zu bieten, ist es bei Azkaban genau andersherum. So ist die Orchestrierung im Falle von Azkaban nur über die WebUI möglich. Oozie hingegen stützt sich auf XML-Dateien oder Bash, um Prozesse zu verwalten und zu planen.

Option 3 – Python-Lösung: Luigi oder Airflow

Luigi und Airflow sind beides in Python geschriebene Workflow-Manager, die als Open-Source-Frameworks verfügbar sind.

Luigi wurde 2011 von Spotify entwickelt und sollte so allgemein wie möglich gehalten werden – im Gegensatz zu Oozie oder Azkaban, die für Hadoop gedacht waren. Der Hauptunterschied zu den beiden anderen ist, dass das Definieren von Aufgaben in Luigi ausschließlich code- und nicht GUI-basiert ist. Die ausführbaren Workflows werden alle durch Python Code dargestellt und die Benutzeroberfläche dient nur der Verwaltung. Diese WebUI von Luigi bietet dabei eine hohe Benutzerfreundlichkeit, wie das Suchen, Filtern oder Überwachen der Graphen und Aufgaben.

Ähnlich verhält es sich mit Airflow, das von Airbnb entwickelt und 2015 freigegeben wurde. Außerdem wurde es 2016 in den Apache Incubator aufgenommen. Wie Luigi ist es ebenfalls code basiert und verfügt über eine Benutzeroberfläche, die auch hier wieder die Endnutzerfreundlichkeit erhöht. Außerdem verfügt es über einen integrierten Scheduler, so dass man nicht auf Cron angewiesen ist.

Unsere Entscheidung

Unser erstes Kriterium für die weitere Filterung war, dass wir einen code basierten Orchestrator wollten. Auch wenn grafische Schnittstellen relativ einfach zu handhaben sind und man sich schnell zurechtfindet, würde dies zu Lasten einer langsameren Entwicklung gehen. Außerdem wäre das Bearbeiten und Erweitern zeitaufwändig, wenn jede einzelne Anpassung per Mausklick erfolgen müsste, anstatt Funktionen oder Codeschnipsel wiederzuverwenden. Deshalb haben wir uns gegen Option 1 entschieden – den lokalen Cloud-Orchestrator. Der Verlust an Flexibilität sollte nicht unterschätzt werden. Alle Erfahrungen und Skills, die wir mit einem unabhängigen Orchestrator gewonnen haben, können wahrscheinlich auf jedes andere Projekt übertragen werden. Dies wäre bei einem cloud-nativen Orchestrator nicht der Fall, da er an die spezifische Umgebung gebunden ist.

Der wichtigste Unterschied zwischen den beiden anderen Optionen ist die Programmiersprache, in denen sie arbeiten. Luigi und Airflow sind Python basiert, während Oozie und Azkaban auf Java und Bash-Skripten basieren. Auch diese Entscheidung war leicht zu treffen, denn Python ist eine hervorragende Skriptsprache, die leicht zu lesen, schnell zu erlernen und einfach zu schreiben ist. Unter dem Aspekt der Flexibilität und Skalierbarkeit bot uns Python einen besseren Nutzen als die (kompilierte) Programmiersprache Java. Außerdem musste die Workflow-Definition entweder über eine grafische Benutzeroberfläche (wieder) oder über XML erfolgen. Auf diese Weise konnten wir auch Option zwei ausschließen.

Abschließend bliebt nur zu klären, ob Spotifys Luigi oder Airbnbs Airflow zur Anwendungen kommen sollte. Es war eine Entscheidung zwischen dem ausgereiften und stabilen (Luigi) oder dem jungen Star (Airflow) unter den Workflow-Managern. Beide Projekte wurden nach wie vor gepflegt und sind auf GitHub sehr aktiv, mit über mehreren tausend Commits, mehreren hundert Stars und mehreren hundert Mitwirkenden. Nichtsdestotrotz gab es einen Aspekt, der für unsere Entscheidung ausschlaggebend war – Cron. Luigi kann Jobs (Aufgaben) nur mit Hilfe von cron planen, im Gegensatz zu Airflow, das einen integrierten, advanced Scheduler hat. Aber was ist überhaupt das Problem mit Cron?

Cron funktioniert gut, wenn Sie eine Aufgabe zu einer bestimmten Zeit erledigen wollen. Sobald Sie jedoch mehrere Aufträge planen wollen, die voneinander abhängen, wird es schwierig. Cron berücksichtigt diese Abhängigkeiten nicht. Nehmen wir an, wir brauchen einen Job, der alle fünf Minuten läuft und einige Echtzeitdaten aus einer Datenbank abgreift. Wenn nichts schief geht und die Laufzeit der Jobs bekannt ist (und sich nicht ändert), werden keine Probleme entstehen. Ein Job wird gestartet, er wird beendet, der nächste startet und so weiter. Was aber, wenn die Verbindung zur Datenbank nicht funktioniert? Auftrag eins wird gestartet, aber nie beendet. Fünf Minuten später wird der zweite Job das Gleiche tun, während Job eins noch aktiv ist. Dies kann sich fortsetzen, bis der gesamte Rechner durch nicht beendete Aufträge blockiert ist oder abstürzt. Mit Airflow könnte ein solches Szenario leicht vermieden werden, da es den Start neuer Aufträge automatisch stoppt, wenn die Anforderungen nicht erfüllt sind.

Zusammenfassung unserer Entscheidung

Wir haben uns für Apache Airflow gegenüber den anderen Alternativen entschieden, weil

  1. Kein Cron – Mit Airflows integriertem Scheduler müssen wir uns nicht auf Cron verlassen, um unsere DAG zu planen, und verwenden nur ein Framework (nicht wie Luigi).

  2. Code-Basierend – In Airflow werden alle Workflows, Abhängigkeiten und das Scheduling in Python Code ausgeführt. Daher ist es relativ einfach, komplexe Strukturen aufzubauen und die Abläufe zu erweitern.

  3. Sprache – Python ist eine Sprache, die man leicht erlernen kann und die in unserem Team vorhanden war.

Daher erfüllt Airflow alle unsere Anforderungen. Wir haben damit einen Orchestrator, der den Workflow, den wir mit Python Code definieren, im Auge behält. Daher können wir den Workflow auch leicht in jede Richtung erweitern – mehr Daten, mehr Batches, mehr Schritte im Prozess oder sogar auf mehreren Maschinen gleichzeitig ausweiten, sind kein Problem mehr. Darüber hinaus bietet Airflow auch eine schöne visuelle Oberfläche des Workflows, sodass man ihn auch leicht überwachen kann. Und schließlich erlaubt Airflow den Verzicht auf Cron, da es mit einem nativen (advanced) Scheduler ausgestattet ist. Dieser kann nicht nur eine Aufgabe starten, sondern behält auch den Überblick über alle definierten Abhängigkeiten und ist in seinen Ausführungseigenschaften stark anpassbar, was zusätzliche Flexibilität bedeutet.

Im zweiten Teil dieses Blogs schauen wir uns Airflow genauer an, erklären, wie man es verwendet und wie man es für verschiedene Anwendungsfälle konfiguriert.

Marvin Taschenberger Marvin Taschenberger

Erfahre mehr!

Als eines der führenden Unternehmen im Bereich Data Science, Machine Learning und KI begleiten wir Sie in die datengetriebene Zukunft. Erfahren Sie mehr über statworx und darüber, was uns antreibt.