Einleitung
Mit der Verwaltung von Daten kommt auch immer das Risiko, dass die Daten fehlerhaft sind. Daher sind für eine hohe Datenqualität Validierungen unerlässlich. Validierungen können primitive Checks sein, beispielsweise ob ein Eintrag fünf Buchstaben hat, das Zahlenfeld wirklich eine Zahl enthält, aber auch weniger hart definierte Bedingungen wie z.B. ob der Eintrag in einer Referenztabelle angelegt ist. Beim Nachschlagen von Referenzdaten kann es zu Änderungen dieser kommen, was eine erneute Überprüfung vorher abgelehnter Datensätze nötig macht.
Im Folgenden soll unsere automatisierte Lösung solcher Problemstellungen vorgestellt werden. Die Validierungen finden auf einer Azure Databricks Deltalake Plattform statt. Die Prozesse sind mit Apache Airflow orchestriert, und die Daten werden mit PySpark verarbeitet.
Aufgaben der Fehlerlöselogik
Das Lösen von Fehlern erfordert zunächst einmal Kenntnis der zu lösenden Fehler. Wir loggen fehlerhafte Datensätze in unterschiedlichen, jeweils pro Prozess angelegten, Fehlertabellen , vorerst ohne eine zentrale Übersicht. Die erste Aufgabe ist es, aus den Eintragungen der Fehlertabellen und Zieltabellen ungelöste und gelöste Fehler zu bestimmen. Informationen über die Status der Fehler werden im Anschluss in einer zentralen Metadatentabelle zusammengetragen. In unserem System wurden werden die Prüfungen und Fehler individuell und manuell angelegt, daher müssen die Metadaten zur Prüfung der Lösbarkeit eines Fehlers ebenfalls individuell je Fehler angelegt werden. Diese Metadatensätze werden am besten direkt beim Anlegen der Validierung mit erstellt. Sie können aber auch im Nachhinein angelegt werden. Das erfordert jedoch Analysen der bestehenden Validierungen. Wir haben durch die Analysen einige unbemerkte Implementierungslücken offengelegt und konnten diese schließen noch bevor Fehler auftreten konnten. Insbesondere in großen und/oder komplexen Systemen können solche spezifischen Analysen Fehler aufdecken und helfen dabei, das System für die Zukunft resilienter zu machen.
Um Fehler auch effektiv lösen zu können, braucht es einen Mechanismus, der jenen Prozess starten kann, der den Validierungsfehler ursprünglich aufgezeigt hat. Der Ladeprozess lädt den Fehler aus der Fehlertabelle und schreibt ihn nach erneuter Validierung in die Zieltabelle.
Zusammenfassend ergeben sich die folgenden zu lösenden Aufgaben:
- Aufbau einer zentralen Übersicht für gegenwärtig offene Fehler.
- Aufbau eines Metadatenkonstrukts, das die Lösungsbedingungen der individuellen Fehler abbildet.
- Aufbau einer Funktion zum Auslesen offener Fehler und Nutzung des Metadatenkonstrukts zur Prüfung auf Lösbarkeit der offenen Fehler.
- Aufbau einer Funktion, um entsprechend Ladeprozesse mit lösbaren Fehlern erneut starten zu können.
Architektur
Das Grundkonzept der Logik ist im folgenden Bild dargestellt:

Unsere Implementierung enthält einige Kernkomponenten:
- Aufruf der Löselogik nach jedem relevanten Prozess
- Eine Tabelle mit Einträgen über offene Fehlertypen, als Übersicht für derzeit offene Fehler
- Eine Tabelle mit den Bedingungen für die Lösbarkeit von Fehlern
- Eine Trigger-Mechanik für die Ladeprozesse
Metadaten, sowie zu verarbeitende und verarbeitete Daten werden auf Microsoft Azure Storage Accounts als Blobs gespeichert. Die Verwaltung dieser erfolgt über Azure Databricks als externe Tabellen. Die Selektion der Metadaten für die Prozesse wird über Python geleistet. Sie werden beim Start an das dem Prozess zugehörige Notebook übergeben. Im Notebook findet dann die Datenverarbeitung über PySpark Dataframes statt.
Die meisten Prozesse werden angestoßen infolge der Registrierung eines angelieferten Files durch einen Apache Airflow Sensor Operator. Diese Mechanik wurde auf ok-Files erweitert, welche durch die Trigger-Mechanik der Fehlerlöselogik erzeugt werden. Der, durch das ok-File spezifizierte, Prozess wird gestartet, und potenziell weitere Prozesse flussabwärts werden ebenfalls gestartet.
Lebenszyklus eines Validierungsfehlers
Folgen wir nun einem beispielhaften Datensatz einmal durch die Logiken. Es handelt sich um eine Zahlung mit den Feldern SENDER, RECEIVER, DATE und AMOUNT (z.B. „Marc, Peter, 20240101, 12.3“). Das File mit dem Datensatz wird in den Eingangsspeicher geliefert.
Die auf einer Microsoft Azure Virtual Maschine laufende Airflow Instanz enthält einen DAG, dessen Sensor im Eingangsbereich nach ok-Files und Daten-Files für die zugehörigen Prozesse sucht.

Das Daten-File wird bemerkt, und der zugehörigen Ladeprozess in die Global Staging Area (GSA) wird gestartet. Dieser validiert, dass die Daten des Files in das zugehörige Schema passen. Während des Ladeprozesses in die Valid Data Area (VDA) wird überprüft, ob der RECEIVER in der Referenztabelle REF_RECEIVER enthalten ist, ob SENDER in REF_SENDER enthalten ist, und ob DATE ein valides Datum ist. Im Beispiel ist „Peter“ nicht in der REF_RECEIVER hinterlegt, und der Eintrag wird in die Fehlertabelle geschrieben mit dem Fehlercode „INVALID_RECEIVER“. Beim nächsten Prozessdurchlauf wird der Datensatz aus der Fehlertabelle zusammen mit neuen Daten der GSA geladen. In der Fehlerübersichtstabelle wird ein Eintrag angelegt, dass für den Ladeprozess der Fehler „INVALDI_RECIEVER“ aktiv ist. Der Fehler wird zusätzlich über unsere Logging Lösung rapportiert, siehe hierzu „Ein intelligentes Cloud Logging-Framework: Effizienz und Erweiterbarkeit mit Azure Functions“.
Aktualisieren der Referenzdaten
Der Fachbereich wird nun festlegen, dass „Peter“ ein valider Empfänger ist, und nur der Eintrag in der Referenztabelle vergessen wurde. „Peter“ wird als Empfänger angelegt, die Referenzdaten erneut angeliefert und in GSA sowie VDA geladen. Am Ende des VDA-Ladeprozesses wird überprüft, welche Fehler in der Fehlerübersichtstabelle als offen registriert sind, und welche davon als durch den VDA-Ladeprozess der REF_RECEIVER lösbar im Metadatenkonstrukt hinterlegt sind. Der Fehler „INVALID_RECEIVER“ ist hinterlegt und es wird geprüft, ob der aufgetretene Fehler gelöst werden kann. In den Metadaten können für die Prüfung notwendige Informationen hinterlegt sein:
- Welche Funktion muss für die Prüfung genutzt werden.
- Auf welche Spalten soll ein Join durchgeführt werden.
- Welche Spalten müssen hergeleitet werden.
- Zusätzliche Bedingungen, die erfüllt sein müssen.
Erhält man am Ende der Prüfung mindestens einen validen Eintrag, so gilt die Prüfung als erfolgreich.

In unserem Fall ist „Peter“ jetzt hinterlegt, und die Prüfung war erfolgreich. Da der Fehler nun lösbar ist, wird ein ok-File für den Prozess angelegt, der den Fehler warf.
Lösen des Fehlers
Wie zuvor das Datenfile, registriert derselbe DAG das ok-File, überspringt den GSA-Ladeprozess und startet direkt den VDA-Ladeprozess.

Der Eintrag wird aus der Fehlertabelle geladen und erfolgreich validiert. Am Ende des VDA-Ladeprozesses wird der Eintrag in die Zieltabelle geschrieben, und in der Fehlertabelle werden die korrespondierenden Einträge als gelöst markiert. Die Logging-Logik der Fehler prüft die Updates und Inserts und stellt fest, dass der Fehler gelöst ist und markiert in der Fehlerübersichtstabelle den Fehler als gelöst, damit keine unnötigen weiteren Überprüfungen stattfinden.
Da man hier die Orchestrierung doppelt verwendet, werden auch potenziell notwendige weitere Ladeprozesse flussabwärts mit ausgeführt.
In der Praxis gibt es zudem Fehler, die durch flussaufwärts liegende Prozesse gelöst werden können. In diesen Fällen werden keine Metadaten für die Lösungsbedingungen hinterlegt. Es kommt zu keinen unnötigen zweiten Durchläufen der Prozesse.
Die Trigger-Mechanik ist auch anderweitig nutzbar. Wenn z.B. ein Job zu bestimmten Zeitpunkten laufen soll, kann ein zweiter DAG zu diesen Zeitpunkten die Trigger-Mechanik aufrufen und so die prozessstartenden ok-Files erzeugen.
Vorteile und Nachteile
Unsere Lösung bietet einige attraktive Vorteile, wie z.B.:
- Unser Framework ist zu 90% Metadaten getrieben, sodass mit nur 3 Prüffunktionen über 100 Fehler auf Lösbarkeit geprüft werden können.
- Einfache Nachschlagefehler können automatisiert gelöst werden.
- Durch eine automatisierte Prüfung löst das System offene Fehler schneller, als wenn ein Mensch den Prozess manuell anstoßen müsste. In dem Zusammenhang ist die automatisierte Lösung auch weniger fehleranfällig.
- Es wird weniger Personal zum Lösen von Fehlern benötigt, wodurch mehr Zeit in andere Verbesserungen investiert werden kann.
Ein Nachteil der Implementierung ist der Folgende:
- Für jede Fehlerart ist ein eigener manuell erzeugter Eintrag im Metadatenkonstrukt notwendig.
Neben den gelisteten Vor- und Nachteilen verfügt das Konzept über einige Aspekte, die sich einer klaren Zuordnung verweigern:
- Die Abgrenzung einzelner Fehler und ihre genaue Erzeugung muss in den Daten widergespiegelt werden. Ein Wiederverwenden von Fehlercodes für mehrere ähnliche, aber nicht identische Fehler, ist nicht mehr möglich. Je nach bisheriger Vergabe von Fehlercodes, kann dies ein Vorteil oder Nachteil sein. Ist jedoch erstmal jeder Fehler individualisiert, ist es definitiv ein Vorteil, da man zu einer sauberen Fehlerverwaltung gezwungen ist.
- In unserem Fall war es ratsam teils neue Spalten für Werte in den Fehlertabellen anzulegen, die zur Herleitung weiterer Werte benötigt werden. Die neuen Spalten haben zu einer besseren Nachvollziehbarkeit der Fehler geführt, im Vergleich zu dem Fall, dass ein Mensch sich die Daten nochmal genauer ansehen muss. Dies kann daher als Vorteil und Nachteil gewertet werden.
Fazit
Unsere Lösung für automatisiertes Fehlerlösen beschleunigt das Lösen von Fehlern. Die Automatisierung reduziert langfristig Kosten, da der Betrieb vom System vereinfacht wird. Eine konsequente Implementierung führt zu gepflegten Metadaten, was eine bessere Übersicht im System ermöglicht. Die Trennung von Orchestrierung in Airflow und Fehlerlöselogik in Databricks ermöglicht eine Segmentierung der Airflow-DAGs in kleine logische Einheiten.
Aus dem Betrieb des Systems, in dem es gerade im Einsatz ist, ist das automatisierte Fehlerlösen nicht mehr wegzudenken.