Tabelle 1: Teilliste der Benutzer-Onboarding-Erfahrungen
Die Lücken in der obigen Tabelle – die meisten Räume – stellen Lücken dar, in denen es noch keine Selbstbedienung gibt. In diesen Fällen erfordert die Erstellung einer End-to-End-Datenpipeline das Schreiben von benutzerdefiniertem Code, um die Lücken zu schließen. Bei Streaming-Datenpipelines umfasst dies das Schreiben von Stream-Verarbeitungsaufträgen.
Um beispielsweise eine End-to-End-Datenpipeline zu erstellen, die Daten von Espresso in Pinot überträgt, haben wir Self-Service-Lösungen für den Hopfen Espresso→Brooklin und für den Hopfen Kafka→Pinot, aber nicht für den Hopfen Brooklin→Kafka zwischen. Ein Entwickler müsste einen benutzerdefinierten Stream-Verarbeitungsjob schreiben und implementieren, um seinen Brooklin-Datenstream in ein Kafka-Thema zu replizieren. Für solche Zwecke gibt es eine Reihe von Samza- und Beam-Jobs.
Die durch diese Datenpipelines gestreamten Datensätze müssen häufig in ein praktischeres Format umgewandelt werden. Beispielsweise wird bei der Pinot-Aufnahme standardmäßig davon ausgegangen, dass Datensätze flach sind und Feldnamen und -typen aufweisen, die mit der Pinot-Tabellendefinition kompatibel sind. Es ist unwahrscheinlich, dass sich ein Espresso-Tisch und ein Pinot-Tisch in diesen Details einig sind. Diese Art von Nichtübereinstimmung kann zwischen jedem Systempaar auftreten. Daher beinhalten Datenpipelines häufig eine Stream-Verarbeitungslogik, um Datensätze eines Schemas in ein anderes umzuwandeln, unnötige Datensätze herauszufiltern oder zusätzliche Felder zu löschen.
Das bedeutet, dass Datenpipelines fast immer irgendeine Form der Stream-Verarbeitung in der Mitte erfordern. Wir haben diese in der Vergangenheit als zwei unterschiedliche Technologien betrachtet (z. B. Brooklin vs. Samza) und es den Entwicklern überlassen, sie miteinander zu verbinden. Um ein End-to-End-Datenpipeline-Erlebnis zu bieten, benötigen wir eine Möglichkeit, Stream-Verarbeitung und Datenpipelines in einem einzigen Konzept zu kombinieren.
Flink tritt auf
Wir haben es kürzlich adoptiert Apache Flink bei Linkedin und Flink SQL haben die Art und Weise verändert, wie wir über Datenpipelines und Stream-Verarbeitung denken. Flink wird oft als Stream-Verarbeitungs-Engine angesehen, und in der Vergangenheit haben die APIs dies widergespiegelt. Aber seit der Einführung des Tabellen-API und Flink SQL hat sich Flink weiterentwickelt, um allgemeinere Datenpipelines zu unterstützen.
Dies ist zum großen Teil auf das Konnektorkonzept der Table API zurückzuführen, das den Konnektoren von Brooklin oder Kafka Connect nicht unähnlich ist. Konnektoren sind der Klebstoff zwischen verschiedenen Systemen und daher mit Datenpipelines verbunden. Bis zu einem gewissen Grad fasst die Table API die Anwendungsfälle von Brooklin zusammen, indem sie Connectors in eine konvergente Stream-Verarbeitungsplattform einbindet.
Das bedeutet, dass wir Datenpipelines und Stream-Verarbeitung in derselben Sprache (SQL) ausdrücken und sie in derselben Laufzeit (Flink) ausführen können. End-to-End-Datenpipelines, die normalerweise mehrere Systeme umfassen und benutzerdefinierten Code erfordern, können als Teil von Flink SQL geschrieben und auf einmal bereitgestellt werden.
Auf dem Weg zu deklarativen Datenpipelines
Aus Benutzersicht ist das ideale End-to-End-Erlebnis eine einzige Autorensprache (z. B. Flink SQL) für eine einzelne Laufzeit (z. B. Flink) auf einem einzigen großen Cluster. Benutzer möchten eine Datenpipeline bereitstellen mit kubectl apply -f my-pipeline.yaml. Die Realität ist jedoch deutlich komplexer. Eine einzelne End-to-End-Datenpipeline bei LinkedIn kann mehrere speziell entwickelte Datenebenensysteme umfassen (z. B. Brooklin, Kobold), laufen auf mehreren Stream-Verarbeitungs-Engines (z. B. Samza, Flink) und kommunizieren mit mehreren Speichersystemen (z. B. Espresso, Venice). Für jede davon sind möglicherweise manuelles Onboarding, benutzerdefinierter Code, zwingende API-Aufrufe usw. erforderlich.
Ausgehend von der idealen Benutzererfahrung und rückwärts arbeitend können wir uns ein deklaratives Modell für End-to-End-Datenpipelines vorstellen. Dies würde Datenpipelines als ein einziges Konstrukt darstellen, sie jedoch durch die Zusammenstellung der erforderlichen Komponenten aus der Datenebene und der Rechenschicht implementieren. Wenn die Datenpipeline eine Stream-Verarbeitung erfordert, könnten wir automatisch einen Flink-Job bereitstellen. Wenn für einen Teil der Datenpipeline ein Genehmigungs- oder Überprüfungsprozess erforderlich ist, können wir den Workflow automatisch auslösen.
Wenn man sich das Kubernetes-Ökosystem ansieht, ist klar, dass dies eine anspruchsvolle Lösung erfordern würde Operator. Dies würde eine benutzerdefinierte Ressourcenspezifikation (im Wesentlichen eine YAML-Datei) in verschiedene physische Ressourcen auf der Datenebene umwandeln. Letztendlich würde eine einzelne Pipeline-Spezifikation zu neuen Flink-Jobs, Kafka-Themen usw. führen.
Es ist jedoch nicht schwer, sich die Verbreitung komplexer Konfigurationen vorzustellen, die sich aus einem solchen Modell ergeben können. Es kann schön sein, eine einzige YAML-Datei zu haben, aber nur insofern, als diese YAML-Datei selbst einfach ist.
Um dieses Problem zu lösen, haben wir begonnen, uns mit der Darstellung von End-to-End-Datenpipelines in SQL zu befassen. Bei LinkedIn verwenden wir in großem Umfang Streaming-SQL, aber vorhandenes SQL drückt nur einen „Sprung“ einer Datenpipeline aus, z. B. von einem Kafka-Thema zu einem anderen. Dies hat zu Datenpipelines geführt, die Hunderte von SQL-Anweisungen umfassen. Im Idealfall könnte eine gesamte Datenpipeline als ein einzelnes Konstrukt auf hoher Ebene kodifiziert werden. Was wäre, wenn eine gesamte End-to-End-Multi-Hop-Datenpipeline nur eine SQL-Abfrage wäre?
Hoptimator: SQL-basierter Multi-Hop-Datenpipeline-Orchestrator
Wir haben einen experimentellen Datenpipeline-Orchestrator namens Hoptimator entwickelt. Es handelt sich im Wesentlichen um einen hochentwickelten Kubernetes-Operator, der auf der Grundlage von SQL-Abfragen End-to-End-Multi-Hop-Datenpipelines erstellt. Das Benutzererlebnis von Hoptimator basiert auf einem übergeordneten Konzept, das wir „Abonnements“ nennen und eine materialisierte Ansicht darstellen. Bei einem Abonnement erstellt Hoptimator automatisch eine Datenpipeline, um die entsprechende Ansicht zu verwirklichen. Dies ermöglicht Entwicklern die Erstellung komplexer Datenpipelines mit verblüffender Einfachheit: