Einleitung
In der heutigen schnelllebigen Datenlandschaft stehen Unternehmen vor der Herausforderung, eine wachsende Flut von Daten aus verschiedenen Quellen effizient zu integrieren. Allerdings verlangt die Komplexität von Cloud-basierten Lösungen und diversen Datenformaten nach flexiblen und effizienten Ansätzen für den Geschäftserfolg. Hier bieten metadatengetriebene Pipelines in Data Factory (ADF), ein zentraler Cloud-basierte Datenintegrationsdienst, eine vielversprechende Lösung.
Aber wie kann man die Datenintegration nicht nur bewältigen, sondern auch so gestalten, dass sie zukunftssicher, wartbar und skalierbar ist? In diesem Blogbeitrag enthüllen wir einen Ansatz, der in einem unserer Kundenprojekte beachtliche Erfolge erzielt hat. Unser Ziel war es, die Artefakte in Azure Data Factory so generisch und wieder verwendbar wie möglich zu gestalten, um die Handhabung zu vereinfachen und gleichzeitig die Automatisierung und Effizienz zu maximieren. Entdecken Sie mit uns, wie eine metadatengetriebene Strategie in Azure Data Factory nicht nur technische Hürden überwindet, sondern auch die Effizienz, Wartbarkeit und Skalierbarkeit Ihrer Datenintegrationsprozesse grundlegend transformiert.
Grundlagen der dynamischen Datenintegration in Azure Data Factory
Azure Data Factory bietet verschiedene Möglichkeiten, Artefakte wie Linked Services, Data Sets, Activities und Pipelines generischer und wiederverwendbarer zu machen. Dies eröffnet neue Wege für eine flexible Datenintegration, die weit über starre, manuell konfigurierte Prozesse hinausgeht.
Generischer Linked Service
Als erstes einfaches Beispiel nehmen wir einen Linked Service der sich zu einem Azure Data Lake Storage Gen2 (ADLS) verbinden kann. In dem Screenshot unten lässt sich feststellen, dass alle wichtigen Informationen aus einem dynamischen Inhalt kommen. Keine Informationen werden konkret angegeben. Für den dynamischen Inhalt bietet Azure Data Factory eine eigene Sprache, die sogenannte Expression Language. In unserem Beispiel wird die URL des Storage Accounts, zu dem man sich verbinden möchte, über die Concat-Funktion mit Hilfe des Parameters par_storageAccount erstellt.
Das Resultat ist, dass die Azure Data Factory nun diesen einen Linked Service benutzen kann, um sich mit jedem Storage Account zu verbinden. Daraufhin muss man lediglich den Namen des Storage Accounts als Parameter mitgeben. Eine weitere Voraussetzung ist, dass die Managed Identity der Data Factory die nötige Berechtigung auf dem Storage Account hat.
Somit hat man ein wieder verwendbares ADF Artefakt, statt jeweils einen Linked Service pro Storage Account. Dieses Prinzip werden wir jetzt auf alle weiteren Artefakte und Features der Datenintegration mit Azure Data Factory anwenden.
Generischer Data Set
Wir haben nun ein Data Set, welches eine CSV Datei auf einem Storage Account beschreibt. Dieses Beispiel baut auf dem vorherigen auf, weil für die Verbindung zu diesem Storage Account der Linked Service aus dem ersten Beispiel benutzt wird. Wir wollen hier jedoch noch nicht den Namen des Storage Accounts fest angeben. Daher wird ein Data Set-Parameter definiert, der den Namen des Storage Accounts an den Linked Service weiter gibt.
Eine weitere wichtige Information ist, wo genau sich die CSV Datei auf unserem Storage Account befindet und wie sie heißt. Diese Information wird über die Parameter par_container, par_directory und par_filename bestimmt. Diese Informationen sind für alle Dateien auf einem Storage Account relevant.
Es gibt aber auch Format spezifische Parameter, die nur für eine CSV Datei angegeben werden müssen. Da wir unseren Data Set für alle möglichen unterschiedlichen CSV Dateien verwenden wollen, müssen wir auch hierfür Parameter definieren. So kann zum Beispiel eine CSV Datei mit Komma als Trennzeichen mit dem selben Data Set beschrieben werden wie eine CSV Datei mit Semikolon. Leider ist es nicht möglich ein Schema dynamisch anzugeben. Wenn man ein Data Set mit einem spezifischen Schema benötigt, muss man einen neues Data Set erstellen.
Generische Pipelines
Möchte ich nun das generische Data Set aus dem letzten Beispiel benutzen, um eine CSV Datei mit Azure Data Factory aus einer beliebigen Quelle auf einen Storage Account zu kopieren, muss ich bei der Verwendung lediglich alle nötigen Informationen unter den Data Set Parametern angeben. Wenn man diese Informationen hier festlegt, hat man jedoch keine generische Pipeline, die für alle ähnlichen Szenarien wiederverwendet werden kann. Die nötigen Informationen zum Ausführen einer bestimmten Aufgabe müssen der Pipeline erst zum Start mitgegeben werden. Um metadatengetriebene Pipelines in Data Factory zu ermöglichen, benötigt man ein geeignetes Metadaten Konzept.
Der Ansatz: Metadatengetriebene Pipelines in Data Factory
Eine generische metadatengetriebene Pipeline in Data Factory ist wie ein Template, das als Blaupause für das Vollrichten einer bestimmten Aufgabe dient. Diese Aufgabe ist meistens die Datenübertragung von einer definierten Quelle zu einem bestimmten Ziel, aber es kann sich zum Beispiel auch um eine Überprüfung der Datenqualität handeln. Hier eine Liste von ausgewählten Beispielen aus unserem Kundenprojekt wofür wir metadatengetriebene Pipelines entwickelt haben:
- Aufrufen einer beliebigen API mit oder ohne Bearer-Token als Autorisierung und abspeichern der Daten als Datei auf einem Storage Account (auch für mehrere APIs möglich, die die selbe Base URL teilen)
- Kopieren von Daten von einem externen SFTP Server auf einen Storage Account
- Schreiben von Daten in einer CSV Datei in eine Azure Postgres Tabelle mit dynamischem Mapping und automatischen Erstellen der Tabelle bei erster Ausführung
- Extrahieren von Daten von SAP via CDC Konnektor von Azure Data Factory in ein bestimmtes Datenformat wie csv oder parquet. Siehe unseren Blogartikel zu SAP Konektoren von Azure Data Factory: https://saracus.com/synvert-saracus-blog/sap-konnektoren-von-azure-data-factory/
- Ausführen eines beliebigen Databricks Notebooks für komplexere Business Logik, mit Übergabe von definierten Parametern
- Schema Validierung und Mapping von Dateien wie csv, txt, parquet
Die Besonderheit dieser Pipelines liegt darin, dass die Pipeline lediglich eine Job-ID als Parameter erhält. Alle weiteren notwendigen Informationen bezieht sie aus einer oder mehreren Metadaten-Konfigurationsdateien. Diese Dateien enthalten alle essenziellen Details über die Datenquelle, das Ziel und das zu übertragende Datenobjekt sowie weitere Parameter für bestimmte Zusatzfeatures einer Pipeline.
Vorteile des metadatengetriebenen Ansatzes
Ein zentraler Vorteil des metadatengetriebenen Ansatzes in Azure Data Factory liegt in der Entwicklung einer universellen Pipeline, die umfassend wiederverwendbar ist. Diese Flexibilität ermöglicht es, bestimmte Funktionen durch Metadaten zu ergänzen, zu modifizieren oder wegzulassen, um die Anforderungen spezifischer Datenverarbeitungsaufgaben zu erfüllen. Ein solches System vereinfacht nicht nur das Testen und die Wartung signifikant, sondern fördert auch eine einheitliche Standardisierung. Die Konfiguration über Metadaten erlaubt zudem eine schnelle und effiziente Anpassung oder Erweiterung der Funktionalitäten. Das ist besonders vorteilhaft bei der Verwaltung zahlreicher, ähnlicher Datenintegrationsprozesse. Beispielsweise können verschiedene Extraktionen aus SAP BW durch eine einzige Pipeline abgewickelt werden, die lediglich unterschiedliche Metadatenkonfigurationen erhält.
Nachteile des metadatengetriebenen Ansatzes
Ein potenzieller Nachteil liegt in der Komplexität der Pipelines, die tendenziell mehr Aktivitäten umfassen können. Dies resultiert anfangs in einem höheren Entwicklungsaufwand, da das Metadatenmodell auf die Projektspezifikationen abgestimmt und gepflegt werden muss. Trotzdem relativiert sich dieser Aufwand über die Zeit, da die Wiederverwendbarkeit der Pipelines und Metadaten für verschiedene Projekte und Kunden die Notwendigkeit umfangreicher Neuentwicklungen minimiert. Meist genügen kleine Anpassungen, um die Systeme an neue Anforderungen anzupassen.
Obwohl der metadatengetriebene Ansatz viele Vorteile bietet, lassen sich nicht alle Szenarien vollständig generalisieren. Insbesondere bei komplexeren Logiken stoßen generische Lösungen an ihre Grenzen. Jedoch können auch hier durch die Übergabe spezifischer Parameter bestimmte Wartungs- und Effizienzvorteile realisiert werden, was die Handhabung erleichtert und die Flexibilität erhöht.
Metadatenkonzept für generische ADF pipelines
Im folgenden wird das Metadatenkonzept für die metadatengetriebenen generischen ADF pipelines beschrieben, welches wir für einen unserer Kunden entwickelt haben. Dieses Konzept ist bereits mit leichten Abwandlungen bei weiteren Projekten im Einsatz. Um das Konzept zu verstehen, ist es hilfreich zuerst auf die Projektanforderungen einzugehen.
In unserem Kundenprojekt bildet unsere Azure Plattform das zentrale Nervensystem, das den Datenfluss unterschiedlicher Dateien zwischen vielen verschiedenen Systemen sicher stellt. Ein bestimmter Datenfluss von einem Quell- zu einem Ziel-System wird als Interface bezeichnet. Dabei kann es sein, dass die Partnersysteme die Daten schicken oder abholen, aber meistens geschieht das Übertragen von Daten durch eine unserer generischen Pipelines. Weil auch noch eine Vielzahl an verschiedenen Protokollen und Dateiformaten vorkommt, macht es Sinn ein Interface aus kleinen wieder verwendbaren Teilen zu erstellen.
Unterteilung der Metadaten
Daher haben wir uns entschieden, die Metadaten horizontal und vertikal aufzuteilen. Horizontal gibt es drei verschiedene Arten von Jobs, wobei ein Job immer einer generischen ADF Pipeline entspricht. Als erstes werden in der Ingestion-Phase Daten vom Quellsystem abgeholt und auf unserem Inbound Storage Account gespeichert. Dann finden in der Processing-Phase alle notwendigen Mappings, Transformationen oder Datenqualitätschecks statt. Schließlich werden die Daten in der Delivery-Phase an das Zielsystem gesendet und dabei nicht mehr verändert.
Vertikal gesehen haben wir verschiedene Metadatentabellen. Sie starten auf der höchsten Ebene sehr allgemein und werden in den tieferen Ebenen immer spezifischer. Als erstes wird auf dem Interface-Level das gesamte Interface an sich beschrieben. Die Standardinformationen für jeden einzelnen Job befinden sich in der Jobtabelle. Weil jeder Job auch sehr spezifische Parameter enthalten kann, wird auf dem Jobparameter-Level hierfür in Form von Key-Value Paaren Platz geboten.
Übersicht über Metadaten mit Beispielen
Im folgenden Schaubild sind alle notwendigen Metadaten. Weil wir manche Parameter je nach Umgebung oder im Englischen Environment (DEVL, INTG, PROD) anpassen müssen, werden diese hier entsprechend klassifiziert. Als nächste Ebene im Schaubild werden die Tabellennamen und deren Relation angegeben. Danach werden kurz verschiedene Parameter Typen klassifiziert, auf die ich in den Beispielen noch näher eingehen werde. Schließlich beschreibt die unterste Ebene den physischen Speicherort der Metadaten, sodass diese auch aktiv genutzt werden können.
Für jeden einzelnen Job werden die notwendigen Metadaten aus den drei bereits genannten Tabellen genommen und in eine einzelne JSON Config Datei abgespeichert. Diese jobId.json Datei wird auf den Metadaten Storage Account abgelegt und kann mit der Angabe der Job ID von einer generischen ADF Pipeline eingelesen werden. Meistens werden auch weitere Metadaten wie zum Beispiel eine Schema Datei, eine Mapping Datei oder auch eine Environment abhängige System Datei benötigt. Diese Dateien können mit Hilfe der Informationen in der jobId.json Datei referenziert und zusätzlich geladen werden. Am besten lässt sich alles an konkreten Beispielen erläutern.
Feature Information
Ein Feature erledigt eine meistens optionale kleine Teilaufgabe einer Pipeline. Ein Beispiel ist die Archivierung einer Datei. Ist der entsprechende Parameter ausgefüllt, wird eine Kopie der Quell- oder Zieldatei an die gewünschte Stelle archiviert. Falls der Parameter nicht ausgefüllt ist, passiert nichts. Für viele Features wie zum Beispiel die dynamische Namensgebung der Zieldatei nimmt die Data Factory Expression Language eine zentrale Rolle ein: https://learn.microsoft.com/de-de/azure/data-factory/how-to-expression-language-functions.
Processing
Diese Parameter kontrollieren die Processing Power einer Copy-Aktivität. Ein Beispiel ist wie stark der Prozess parallelisiert werden soll. Je nach Größe der Datenmengen und Anforderungen an Laufzeit und Kosten, kann man hier entsprechend hoch oder runter gehen. Die Standardwerte werden als globale Parameter abgespeichert, so dass man diese Information nicht überall angeben muss.
Format
Diese Parameter haben wir schon weiter oben in unserem CSV Data Set kennen gelernt. Diese Parameter beschreiben alle formatabhängigen Parameter für die Quell- und/oder Zieldatei. Es ist wichtig diese flexibel anpassen zu können, weil jedes System andere Anforderungen hat.
Connector
Diese Parameter werden in der Job Parameter Tabelle definiert, weil sie spezifisch für gewisse Konnektoren sind. Bei dem SAP CDC Konnektor kann man hier zum Beispiel angeben, welche Spalten man extrahieren möchte oder einen Filter auf die Daten definieren. Für einen API Aufruf kann man zusätzliche Header oder die Request Methode (GET, POST) festlegen.
Global Parameters
Globale Parameter können in Azure Data Factory gesetzt und von allen Pipelines benutzt aber nicht verändert werden. Manche globale Parameter sind Environment spezifisch. Sie können während eines Deployments verändert werden. Das wichtigste Beispiel ist der Parameter par_environment, der mir angibt, ob ich mich auf der Entwicklungs‑, Integrations- oder Produktionsumgebung befinde. Diese Information wird an vielen Stellen benötigt.
Angenommen ich möchte den Namen meines Archiv Storage Accounts in den globalen Parametern abspeichern. Dieser soll archiv[ENVIRONMENT] heißen. Dann speichere den Storage Account Namen als „archiv“ ab. Anschließend nutze ich die Expression Language, um mit par_environment den richtigen Namen für jede Environment zu erstellen.
System Connector und Azure Key Vault Secrets
Hier werden alle Environment abhängigen Parameter für ein bestimmtes externes System abgespeichert. Jedes System bekommt ein Kürzel, das in der jobId.json datei referenziert wird. Zusammen mit dem par_environment Parameter wird dann die richtige Datei eingelesen.
In diesen Dateien stehen alle nötigen Informationen, um sich mit dem jeweiligen System zu verbinden. Zusätzlich können noch weitere Environment und System abhängige Parameter definiert werden. Ein gutes Beispiel sind die Informationen, um sich mit einem SFTP Server zu verbinden. Hier wird der Host Name, der Port und die Daten zum Anmelden benötigt. Sensitive Informationen wie Passwörter werden als Secrets in einem Azure Key Vault verwaltet. Hier wird lediglich das Secret referenziert. Anschließend wird das Secret erst zur Laufzeit von der Pipeline aus dem Key Vault extrahiert.
Fazit
Das vorgestellte Metadatenkonzept für generische metadatengetriebene Pipelines in Data Factory hebt die Bedeutung einer strukturierten Verwendung von Metadaten hervor, um Datenflüsse effizient und flexibel zu gestalten. Durch die horizontale und vertikale Aufteilung der Metadaten ermöglicht unser Ansatz eine einfache Wiederverwendbarkeit und Anpassbarkeit von Pipelines, was die Entwicklungsaufwände erheblich reduziert und gleichzeitig die Wartbarkeit verbessert.
Dieses Konzept beweist, dass mit einem gut durchdachten Metadatenansatz komplexe Datenintegrationsprozesse nicht nur vereinfacht, sondern auch skalierbar und zukunftssicher gemacht werden können. Unternehmen profitieren von einer gesteigerten Effizienz bei der Datenverarbeitung und legen damit den Grundstein für Innovationen und die Anpassung an neue Technologien.
Kurz gesagt, das Metadatenkonzept für metadatengetriebene Pipelines in Data Factory ist ein Schlüsselelement für die Realisierung agiler und effizienter Datenpipeline-Projekte, das die Tür zu einer optimierten Datenverarbeitung weit öffnet.