Kapitel 1. Grundlagen des Streaming

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Die Reise des Helden beginnt immer mit einem Ruf. Auf die eine oder andere Weise muss ein Führer kommen und sagen: "Schau, du bist im Schlaraffenland. Wache auf. Komm mit auf eine Reise. Es gibt einen ganzen Aspekt deines Bewusstseins, deines Wesens, der noch nicht berührt wurde. Du bist also hier zu Hause? Na ja, es gibt nicht genug von dir dort." Und so fängt es an.

Joseph Campbell, Reflexionen über die Kunst des Lebens: Ein Joseph Campbell-Begleiter

Die Streaming Database ist ein Konzept, das aus über einem Jahrzehnt der Datenverarbeitung und -bereitstellung entstanden ist. Die Entwicklung, die zum Aufkommen von Streaming-Datenbanken geführt hat, ist in der breiteren Geschichte der Datenbankmanagementsysteme, der Datenverarbeitung und den sich ändernden Anforderungen des digitalen Zeitalters verwurzelt. Um diese Entwicklung zu verstehen, machen wir eine historische Reise durch die wichtigsten Meilensteine, die die Entwicklung von Streaming-Datenbanken geprägt haben.

Der Aufstieg des Internets und das explosive Wachstum digitaler Daten im späten 20. Jahrhundert führten dazu, dass skalierbarere und flexiblere Datenmanagementlösungen benötigt wurden. Data Warehouses und stapelverarbeitende Frameworks wie Hadoop entstanden, um die Herausforderungen der großen Datenmengen in dieser Zeit zu bewältigen.

Der Begriff "Big Data" wurde und wird nicht nur für die Größe der Daten verwendet, sondern auch für alle Lösungen, die extrem große Daten speichern und verarbeiten. Große Daten passen nicht auf einen einzigen Computer oder Server. Du musst sie in kleinere, gleich große Teile aufteilen und auf mehreren Computern speichern. Systeme wie Hadoop und MapReduce wurden populär, weil sie eine verteilte Speicherung und Verarbeitung ermöglichen.

Dies führte zu der Idee, verteiltes Streaming zu nutzen, um große Datenmengen in Hadoop zu übertragen. Apache Kafka war ein solcher Messaging-Dienst, der für die Verarbeitung großer Datenmengen entwickelt wurde. Er ermöglichte nicht nur die Übertragung von Daten von System zu System, sondern auch den Zugriff auf Daten in Bewegung - in Echtzeit. Diese Entwicklung führte zu einer neuen Welle der Nachfrage nach Echtzeit-Streaming-Anwendungsfällen.

Neue Technologien, wie Apache Flink und Apache Spark, wurden entwickelt und konnten diese neuen Erwartungen erfüllen. Als verteilte Frameworks für Stapelverarbeitung und Streaming konnten sie Daten über viele Server hinweg verarbeiten und Analyseergebnisse liefern. In Verbindung mit Kafka bot das Trio eine Lösung, die analytische Streaming-Anwendungen in Echtzeit unterstützen konnte. Auf Stream-Prozessoren gehen wir in Kapitel 2 näher ein.

Mitte der 2010er Jahre kamen einfachere und bessere Streaming-Paradigmen auf, um den Umfang der Echtzeit-Datenverarbeitung zu erhöhen. Dazu gehörten zwei neue Streamverarbeitungs-Frameworks, Apache Kafka Streams (KStreams) und Apache Samza. KStreams und Samza waren die ersten, die materialisierte Ansichten implementierten, wodurch der Stream mehr wie eine Datenbank aussah und sich auch so anfühlte.

Martin Kleppmann hat die Verknüpfung von Datenbanken und Streaming noch weiter vorangetrieben. In seinem Vortrag "Turning the Database Inside-Out" aus dem Jahr 2015 beschrieb er eine Methode zur Implementierung von Stream Processing, bei der interne Datenbankfunktionen in Echtzeit-Streams externalisiert werden. Dieser Ansatz führte zu skalierbaren, robusten und Echtzeit-Stream-Processing-Systemen.

Eines der Probleme der Stream-Verarbeitung war (und ist), dass sie schwieriger zu bedienen ist als die Stapelverarbeitung. Es gibt weniger Abstraktionen und viel mehr Technik, die in die Tiefe geht. Um Stream Processing für ihren Anwendungsfall zu implementieren, mussten Dateningenieure nun die Reihenfolge der Daten, die Konsistenz für eine genaue Verarbeitung, Fehlertoleranz, Ausfallsicherheit, Skalierbarkeit und vieles mehr berücksichtigen. Dies wurde zu einer Hürde, die Datenteams davon abhielt, Streaming zu nutzen. Infolgedessen haben sich die meisten dafür entschieden, weiterhin Datenbanken zur Datenumwandlung zu verwenden und die Datenverarbeitung in Stapeln durchzuführen, was jedoch zu Lasten der Leistungsanforderungen geht.

In diesem Buch wollen wir Streaming und Stream Processing für diejenigen zugänglicher machen, die es gewohnt sind, mit Datenbanken zu arbeiten. Wir beginnen, wie Kleppmann es getan hat, mit der Frage, wie man die Datenbank von innen nach außen dreht.

Die Datenbank von innen nach außen drehen

Martin Kleppmann ist ein angesehener Softwareentwickler, der den anregenden Vortrag "Turning the Database Inside-Out" hielt. Er stellte Apache Samza als eine neuere Art der Implementierung von Stream Processing vor, die interne Datenbankfunktionen in Echtzeit-Streams externalisiert. Seine Vordenkerrolle führte zu einem Paradigmenwechsel bei der Einführung von Materialized Views für die Stream-Verarbeitung.

In Wirklichkeit ist es ein heimlicher Versuch, die Datenbankarchitektur, die wir kennen, auf den Kopf zu stellen.

Martin Kleppmann, "Die Datenbank von innen nach außen drehen"

Die Verarbeitung von Datenströmen ist jedoch nach wie vor schwierig, und deshalb haben sich viele Dateningenieure im Laufe der Zeit dafür entschieden, weiterhin Datenbanken für die Datenumwandlung zu verwenden und sie in Batches auszuführen, auch wenn dies bedeutet, dass die SLA-Anforderungen nicht erfüllt werden.

Im weiteren Verlauf dieses Buches werden wir versuchen, Streaming und Stream Processing für Dateningenieure zugänglicher zu machen, indem wir sie in die Datenbank zurückbringen. Aber bevor wir das tun können, müssen wir verstehen, warum Kleppmann die Datenbank auseinandergenommen hat und warum er die spezifischen Datenbankfunktionen in seinem neuen Paradigma gewählt hat, um Echtzeitdatenverarbeitung zu erreichen.

Datenbankfunktionen externalisieren

Kleppmann zwei wichtige Funktionen in der Datenbank identifiziert: das Write-Ahead-Log (WAL) und die materialisierte Ansicht. Wie sich herausstellte, haben diese Funktionen natürlich Streaming-Eigenschaften, die eine bessere Möglichkeit bieten, Daten in Echtzeit zu verarbeiten.

Vorausschauendes Schreiben

Die WAL ist ein Mechanismus, mit dem Datenbanken die Haltbarkeit und Konsistenz von Daten sicherstellen können. Die rotierenden Festplatten, auf die Datenbanken Daten schreiben, bieten keine Transaktionen. Datenbanken stehen also vor der Herausforderung, Transaktionsfähigkeit auf einem Gerät zu gewährleisten, das keine Transaktionen anbietet. Mit WALs können Datenbanken Transaktionsfähigkeit bieten, ohne transaktionsfähige Festplatten zu haben.

Eine Transaktion in einer Datenbank bezieht sich auf eine Abfolge von einer oder mehreren Datenbankoperationen, die als eine einzige Arbeitseinheit ausgeführt werden. Diese Operationen können das Einfügen (INSERT), Ändern (UPDATE) oder Löschen (DELETE) von Daten umfassen (siehe Abbildung 1-1).

][alt
Abbildung 1-1. Ein vorausschauendes Protokoll, das Änderungsereignisse in einer Datenbank aufzeichnet

Die WAL fungiert als Puffer, der überschrieben werden kann, wenn neue Änderungen vorgenommen werden. Der WAL speichert die Änderungen auf der Festplatte, wie in Abbildung 1-2 dargestellt.

][alt
Abbildung 1-2. Datenbank schreibt über das Write-Ahead-Log auf die Festplatte

Wenn du Transaktionen auf der Festplatte speicherst, geht die Datenbank wie folgt vor:

  1. Der Kunde startet eine Transaktion, indem er eine BEGIN Anweisung abgibt.

  2. Die Datenbank schreibt einen Datensatz in die WAL, der anzeigt, dass eine Transaktion begonnen hat.

  3. Der Kunde nimmt Änderungen an den Datenbankdaten vor.

  4. Der Client bestätigt die Transaktion mit einer COMMIT Anweisung.

  5. Die Datenbank schreibt einen Datensatz in die WAL, der anzeigt, dass die Transaktion bestätigt wurde.

  6. Die durch die Transaktion vorgenommenen Änderungen werden auf die Festplatte geschrieben.

Wenn eine Transaktion beginnt, schreibt die Datenbank einen Datensatz in die WAL, der anzeigt, dass die Transaktion begonnen hat. Die Datenbank nimmt dann Änderungen an den Datenbankdaten vor. Die Änderungen werden jedoch erst auf die Festplatte geschrieben, wenn die Transaktion abgeschlossen ist. Wenn die Datenbank abstürzt oder die Stromversorgung unterbrochen wird, können die Änderungen aus dem Protokoll wiedergegeben und die Datenbank in einen konsistenten Zustand versetzt werden.1

Der WAL bietet einen Mechanismus, um Datenbanktransaktionen in Echtzeit zu erfassen, indem er es externen Systemen ermöglicht, ihn zu abonnieren. Einer dieser Anwendungsfälle ist die Notfallwiederherstellung von Datenbanken. Durch das Auslesen der WAL können die Daten in eine sekundäre Datenbank repliziert werden. Wenn die primäre Datenbank ausfällt, können die Datenbank-Clients auf die sekundäre Datenbank ausweichen, die ein Replikat der primären Datenbank ist (siehe Abbildung 1-3).

][alt
Abbildung 1-3. Die WAL wird verwendet, um Daten von einer primären Datenbank auf eine sekundäre Datenbank zu replizieren, falls die primäre Datenbank ausfällt

Da WALs Transaktionen in Echtzeit empfangen, sind sie natürlich perfekt für das Streaming geeignet. Kunden können die WAL abonnieren und ihre Transaktionen an eine Streaming-Plattform weiterleiten, damit andere Systeme sie nutzen können. Diese anderen Systeme können auch Replikate erstellen, die die ursprüngliche Primärdatenbank repräsentieren. Die Semantik des WAL-Konstrukts wird von Streaming-Plattformen wie Kafka in ihrer Implementierung der Speicherung nachgeahmt. Streaming-Plattformen erweitern die Datenbank-WAL nach außen, damit andere Anwendungen und Systeme sie nutzen können.

Es gibt noch weitere Streaming-bezogene Konzepte für die WAL. Nachdem die Transaktionen übertragen wurden, wird die WAL nicht sofort gelöscht. Stattdessen folgt sie einem Prozess, der Checkpointing genannt wird und bei dem die Transaktionen der WAL in regelmäßigen Abständen in die Hauptdatendateien übertragen werden. Das Checkpointing dient mehreren Zwecken. Einer davon ist, sicherzustellen, dass einige festgeschriebene Änderungen dauerhaft in die Datendateien geschrieben wurden, um die Datenmenge zu reduzieren, die bei der Wiederherstellung nach einem Absturz erneut abgespielt werden muss. Das hilft, den Wiederherstellungsprozess zu beschleunigen. Außerdem wächst der WAL im Laufe der Zeit, wenn Transaktionen übertragen werden. Checkpointing hilft dabei, die Größe der WAL zu kontrollieren, indem ein Teil ihres Inhalts in die Datendateien geleert wird. So wird verhindert, dass die WAL zu groß wird und zu viel Speicherplatz verbraucht. Checkpointing und die Wiederholung von Transaktionen sind Funktionen, die du aus ähnlichen Gründen auch in der Stream-Verarbeitung findest.

Wir haben erwähnt, dass das WAL-Konstrukt, das normalerweise intern in der Datenbank lebt, extern in Streaming-Plattformen wie Kafka dargestellt werden kann, die eine WAL-ähnliche Semantik bei der Replikation von Daten vom System zum System bieten.

Streaming-Plattformen

Streaming Plattformen wie Apache Kafka sind verteilte, skalierbare und fehlertolerante Systeme, die für die Verarbeitung von Echtzeit-Datenströmen entwickelt wurden. Sie bieten eine leistungsstarke Infrastruktur für das Aufnehmen, Speichern und Verarbeiten großer Mengen kontinuierlicher Daten aus verschiedenen Quellen.

Die meisten Streaming-Plattformen haben ein Konstrukt namens Partitionen. Diese Konstrukte ahmen die WALs in einer Datenbank nach. Transaktionen werden an Partitionen angehängt wie Transaktionen an ein WAL. Streaming-Plattformen können viele Partitionen haben, um die Stream-Last zu verteilen und eine horizontale Skalierung zu ermöglichen. Partitionen werden in Abstraktionen gruppiert, die Topics genannt werden und in denen Anwendungen Transaktionen entweder veröffentlichen oder konsumieren.

Indem du die Transaktionen auf der Streaming-Plattform veröffentlichst, stellst du sie allen Abonnenten zur Verfügung, die sie konsumieren möchten. Dies wird als Veröffentlichungs- und Abonnementmodell bezeichnet, und ist es wichtig, dass mehrere unterschiedliche Verbraucher diese Transaktionen nutzen können.

Bei anderen Streaming-Plattformen können die Namen dieser Konstrukte anders lauten. In Tabelle 1-1 sind einige alternative Streaming-Plattformen aufgeführt . Apache Kafka ist die heute am häufigsten verwendete Streaming-Plattform. In Apache Kafka wird die Abstraktion dieser Konstrukte als topic bezeichnet, und die untergeordneten Partitionen werden als Partitionen bezeichnet.

Tabelle 1-1. Alternative Streaming-Plattformen
Name der Streaming-Plattform Beschreibung Umsetzung Thema Name Name der Partition Kafka-konform

Memphis

Memphis ist eine Open-Source-Alternative der nächsten Generation zu herkömmlichen Message Brokern.

GoLang

Station

Stream

Nein

Apache Pulsar

Apache Pulsar ist eine Open-Source-Plattform für verteiltes Messaging und Streaming, die ursprünglich bei Yahoo! entwickelt wurde.

Java

Thema

Hauptbuch

Ja - derzeit unterstützt der Pulsar Kafka-Wrapper die meisten Operationen, die die Kafka-API bietet.

Redpanda

Redpanda ist eine Open-Source-Streaming-Plattform, die eine leistungsstarke, skalierbare und zuverlässige Methode zur Verarbeitung von Echtzeit-Datenströmen bietet.

C++

Thema

Trennwand

Ja

WarpStream

WarpStream ist eine Kafka-kompatible Daten-Streaming-Plattform, die direkt auf S3 aufsetzt.

GoLang

Thema

Trennwand

Ja

Gazette

Gazette ist eine leichtgewichtige Open-Source-Streaming-Plattform.

GoLang

Selektor

Zeitschrift

Nein

Pravega

Pravega ist ein Stream-Prozessor, der eine Abstraktion der Streaming Speicherung für kontinuierlich generierte und unbegrenzte Daten bietet.

Java

Stream

Stream Segment

Kafka-Adapter verfügbar

Hinweis

In diesem Buch werden wir die Begriffe "Topic" und "Partition" als Namen für die Konstrukte der Streaming-Plattform verwenden, die Echtzeit-Streaming-Daten enthalten.

Da Kafka heute die beliebteste Streaming-Plattform ist, zeigt die letzte Spalte in Tabelle 1-1, ob die Streaming-Plattform Kafka-Clients unterstützt. So können Anwendungen Kafka gegen eine andere Kafka-kompatible Streaming-Plattform austauschen.

Wie bereits erwähnt, ist eine Partition ein Mechanismus, den Streaming-Plattformen nutzen, um sich selbst zu skalieren. Je mehr Partitionen ein Thema hat, desto besser kann es die Datenlast verteilen. Dadurch können mehr Verbraucherinstanzen die Transaktionen parallel verarbeiten. Die Verteilung der Transaktionen auf die Partitionen erfolgt mithilfe eines Schlüssels, der der Transaktion zugewiesen wird. In Abbildung 1-4 wird der WAL in der Datenbank gelesen und in einem Topic in einer Streaming-Plattform gespeichert - auf einer höheren Abstraktionsebene als nur einer Festplatte.

][alt
Abbildung 1-4. Themen in der Streaming-Plattform können ein WAL nachahmen und für andere Systeme auslagern, um Replikate der ursprünglichen Quelldatenbank zu erstellen

Anstatt die Daten zu speichern, damit andere sie abfragen können, rekonstruiert die Streaming-Plattform die WAL und verteilt die Transaktionen auf separate Partitionen.2 Durch die Rekonstruktion der WAL werden die Transaktionen anderen Datensystemen zugänglich gemacht, um Replikate der primären Datenbank zu erstellen.

Partitionen sind unveränderliche "Append-Only"-Protokolle, die Streaming-Plattformen verwenden, um Transaktionen zu erfassen und bereitzustellen. Viele Verbraucher können sie mit Hilfe von Offsets abonnieren. Offsets entsprechen dem Index oder der Position einer Transaktion in der Partition.3 Jeder Verbraucher des Themas hat einen Offset-Zeiger, um seine Position in der Partition zu verfolgen. So können die Verbraucher die Transaktionen in der Partition in ihrem eigenen Tempo lesen und verarbeiten. Ein Nebeneffekt ist, dass die Streaming-Plattform die Transaktionen in den Partitionen länger aufbewahren muss als Datenbanken ihre Transaktionen in einem WAL aufbewahren. Die Standardaufbewahrung in Kafka beträgt 7 Tage. Das gibt langsamen Verbrauchern viel Zeit, um die Transaktionen im Topic zu verarbeiten. Diese Eigenschaft ist auch konfigurierbar, um eine noch längere Aufbewahrungszeit zu ermöglichen.

In Bezug auf Abbildung 1-4 solltest du über die Veröffentlichung von Transaktionen in einem Topic ganz anders denken als über das Schreiben auf die Festplatte. Das Wichtigste an Topics in einer Streaming-Plattform ist, dass Transaktionen, die in ihnen veröffentlicht werden, immer noch als Streaming angesehen werden. Um das zu erklären, verwenden wir eine Wasser-Metapher. Wenn du Wasser aus einem Wasserhahn trinkst, würdest du es als frisches Wasser betrachten. So ist es auch bei Streaming-Plattformen. Wenn du Transaktionen aus einem Thema konsumierst, gelten sie ebenfalls als frisch. Wenn du dagegen einen Liter Wasser mit nach Hause nimmst und ihn eine Zeit lang nicht trinkst, gilt er als abgestanden. Abgestandenes oder stagnierendes Wasser ist anfällig für Bakterienwachstum und ist unsauber. Der abgestandene Liter Wasser ist eher mit der Stapelung von Daten vergleichbar.

Wenn du deine Wasserhähne hingegen mehr als einen Monat lang nicht benutzt hast, kann das Wasser aus den Wasserhähnen Rost oder Ablagerungen enthalten, was darauf hindeutet, dass das Wasser abgestanden ist. In diesem Fall ist das Wasser, das aus dem Wasserhahn kommt, nicht immer frisch. Streaming-Plattformen verfügen in der Regel über einen Mechanismus, der sie vor abgestandenen Transaktionen schützt. Um zu verhindern, dass veraltete Transaktionen veröffentlicht werden, werden die Themen aufbewahrt. Die Transaktionen können nach einer vom Nutzer der Streaming-Plattform festgelegten Aufbewahrungsfrist gelöscht werden.

Zusammenfassend lässt sich sagen, dass primäre OLTP-Datenbanken beim Speichern auf rotierenden Festplatten natürlich in ein WAL schreiben. WALs können zur Replikation von Daten auf eine sekundäre OLTP-Datenbank für Disaster-Recovery-Szenarien verwendet werden. Streaming-Plattformen wie Kafka können verwendet werden, um das Datenbank-WAL mit Hilfe von Partitionen, die durch Topics abstrahiert werden, zu externalisieren und die Transaktionen, die ursprünglich im WAL waren, anderen Systemen zur Verfügung zu stellen. Diese Systeme abonnieren das Topic, damit sie ihr Replikat der Tabellen in der ursprünglichen primären OLTP-Datenbank genauso aufbauen können wie die sekundäre OLTP-Datenbank (siehe Abbildung 1-5). Streaming-Plattformen können also genutzt werden, um die WALs, die zuvor in den OLTP-Datenbanksystemen verborgen waren, öffentlich zugänglich zu machen - und werden so zu einem Werkzeug für die Synchronisierung deiner Datenbanksysteme im gesamten Unternehmen.

][alt
Abbildung 1-5. Die Partitionen in einem Thema können die Transaktionen aus einer OLTP-Quelldatenbank enthalten und die Transaktionen für andere Systeme veröffentlichen, um Replikat-Tabellen zu erstellen

Mit einem ähnlichen Ansatz können wir materialisierte Ansichten in Stream Processing Plattformen erstellen.

Materialisierte Ansichten

In typischen OLTP-Datenbanken sind materialisierte Ansichten spezielle Arten von Datenbankobjekten, die die Ergebnisse einer vorberechneten Abfrage oder Aggregation speichern. Im Gegensatz zu regulären Ansichten, die virtuell sind und ihre Ergebnisse dynamisch auf der Grundlage der zugrunde liegenden Daten generieren, speichern materialisierte Ansichten die tatsächlichen Daten und sind somit physisch in der Datenbank gespeichert.

Der Zweck von materialisierten Ansichten ist es, die Leistung komplexer Abfragen oder Aggregationen zu verbessern, indem die Ergebnisse vorberechnet und gespeichert werden. Wenn eine Abfrage auf eine materialisierte Ansicht verweist, kann die Datenbank die vorberechneten Daten schnell aus der materialisierten Ansicht abrufen, anstatt sie aus den Basisdatentabellen neu zu berechnen. Dies kann die Ausführungszeit der Abfrage erheblich verkürzen und die Gesamtleistung der Datenbank verbessern, insbesondere bei großen und ressourcenintensiven Abfragen.

Der Materialisierungsprozess in Datenbanken muss normalerweise manuell aktualisiert werden, um die gespeicherten Ergebnisse aktuell zu halten. Beispiel 1-1 zeigt, wie du eine materialisierte Ansicht in einer Postgres-Datenbank, einer beliebten OLTP-Datenbank, aktualisieren kannst.

Beispiel 1-1. Auffrischen einer materialisierten Ansicht in Postgres
REFRESH MATERIALIZED VIEW CONCURRENTLY product_sales;

Durch die Möglichkeit, materialisierte Ansichten zu aktualisieren, sind die gespeicherten Daten immer frisch, d.h. es handelt sich um Echtzeitdaten. Dank dieser Eigenschaft passen materialisierte Ansichten ganz natürlich in Streaming-Frameworks.

Im vorigen Abschnitt wurde beschrieben, dass Streaming-Plattformen Transaktionen aus OLTP-WALs speichern können. Diese Partitionen ahmen das WAL-Konstrukt nach, sodass andere Systeme Replikate von Tabellen in der ursprünglichen OLTP-Datenbank erstellen können. Derselbe Ansatz kann in Stream-Prozessoren angewendet werden, um tabellarische Strukturen aufzubauen (siehe Abbildung 1-6).

][alt
Abbildung 1-6. Replikate können auch in Stream-Prozessoren erstellt werden, so wie andere Systeme Replikate erstellen können

Wir werden in Kapitel 2 mehr über die Stream-Verarbeitung sprechen. Außerdem haben wir Kapitel 3 den materialisierten Ansichten gewidmet, weil sie für Streaming-Datenbanken von großer Bedeutung sind. Um Streaming-Datenbanken am besten zu erklären, hilft es, einen einfachen Anwendungsfall aufzustellen, den wir bis zum Ende verfolgen können. Auf dem Weg dorthin werden wir jedes System identifizieren, das benötigt wird, um das Ziel des Anwendungsfalls zu erreichen.

Anwendungsfall: Clickstream-Analyse

Beginnen wir mit der Definition eines einfachen Anwendungsfalls. Dieser Anwendungsfall wird uns helfen, Streaming-Datenbanken besser zu verstehen, wie sie einen Echtzeit-Anwendungsfall lösen können und welche Vorteile sie bei der Entwicklung einer Echtzeitlösung bieten.

In unserem Anwendungsfall geht es um Clickstream-Daten. Clickstream-Daten sind eine Abfolge von aufgezeichneten Ereignissen, die die Aktionen und Interaktionen von Nutzern aufzeichnen, während sie durch eine Website, Anwendung oder digitale Plattform navigieren. Sie bieten eine detaillierte Aufzeichnung der Klicks, Seitenaufrufe und anderer Interaktionen, die von den Nutzern während ihrer Online-Sitzungen durchgeführt werden.

Clickstream-Daten können für verschiedene Zwecke genutzt werden, z. B. für Personalisierung, gezielte Werbung, Nutzersegmentierung, Betrugserkennung und Conversion-Rate-Optimierung. Sie spielen eine wichtige Rolle in der Webanalyse, der Marketinganalyse, der Nutzererfahrungsforschung und anderen datengesteuerten Disziplinen. In Abbildung 1-7 klickt ein Kunde auf ein Produkt und erzeugt ein Klickereignis, das von einem Microservice erfasst wird. Dieses Klick-Ereignis wird an nachgelagerte Analysezwecke weitergeleitet.

][alt
Abbildung 1-7. Ein Nutzer klickt auf ein grünes T-Shirt und erzeugt ein Klick-Ereignis, das von einem Microservice erfasst wird

In unserem Anwendungsfall klickt ein 24-jähriger männlicher Kunde aus Woodstock, NY, über eine Telefonanwendung auf ein grünes T-Shirt. Unser Ziel ist es, den Endnutzern Clickstream-Daten zur Verfügung zu stellen, damit sie Analysen durchführen und Erkenntnisse gewinnen können, die ihnen helfen, datengestützte Entscheidungen zu treffen.

Nehmen wir an, wir wollen in diesem Beispiel Klick-Ereignisse erfassen und sie mit bestehenden Kunden in Verbindung bringen. Das hilft der Analyse, um gezieltes Marketing zu betreiben und ein persönlicheres Erlebnis zu schaffen.

Wir nennen die Daten, die in eine WAL in einer OLTP-Datenbank eingehen, Transaktionen. Die Klicks, die wir von einer nutzerorientierten Anwendung erfassen, nennen wir in unserem Anwendungsfall Ereignisse. Beide werden schließlich in einer Streaming-Plattform wie Kafka landen, so dass wir sie schließlich zusammenführen können.

Verstehen von Transaktionen und Ereignissen

Bisher haben wir die Daten, die aus einer Datenbank stammen, als Transaktion bezeichnet. Dabei handelt es sich um Einfügungen, Aktualisierungen und Löschungen, die in die WAL und anschließend in ein Topic in einer Streaming-Plattform geschrieben wurden. Wir können diese Transaktionen auch Änderungsereignisse oder einfach Ereignisse nennen. Sie sind Einfüge-, Aktualisierungs- und Löschereignisse, genau wie ein Klick auf eine Anwendung ein Ereignis ist.

Auch wenn es sich bei beiden um Ereignisse handelt, ist es sehr wichtig zu verstehen, dass es sich um unterschiedliche Arten von Ereignissen handelt. Das eine wird durch Änderungen an den Tabellen in einer Datenbank ausgelöst, das andere durch Aktionen in einer Anwendung. Um die Unterschiede zu erkennen, müssen wir kurz auf das domänenorientierte Design eingehen.

Domänenorientiertes Design

In der Software modellieren die Ingenieure ihre Anwendungen mit Objekten, die in ihrem Geschäftsfeld existieren. Wenn zu deinem Geschäft zum Beispiel auch Kunden gehören, erstellst du in der Anwendung ein Objekt, das einen Kunden darstellt. Das tust du für jedes Objekt, das zu deinem Geschäftsfeld gehört.

Lass uns ein Modell erstellen, das die Objekte in unserem Anwendungsfall beschreibt. Kunden und Produkte sind Objekte, die Teil des Domänenmodells sind, das diese Anwendung definiert. Diese Objekte werden Entitäten genannt. Entitäten leben in der OLTP-Datenbank und unterliegen Änderungsereignissen wie Einfügungen, Aktualisierungen und Löschungen.

Ereignisse wie Klickereignisse erfassen die Interaktionen zwischen den Entitäten in der Anwendung. In unserem Beispiel klickt ein Kunde auf ein Produkt. Der Kunde und das Produkt sind die Objekte, und die Aktion ist der Klick auf das Produkt. Dies wird in Abbildung 1-7 dargestellt.

Wir können die Struktur eines Satzes nutzen, um diese Beziehung zu beschreiben. Ein Satz enthält ein Subjekt, ein Verb und ein Objekt. Das Subjekt in einem Satz ist normalerweise die Person, die eine Handlung ausführt. Das Verb beschreibt die Handlung. Das Objekt schließlich ist die Entität, auf die die Handlung angewendet wird. In unserem Anwendungsfall lautet der Satz:

The customer clicked on a product.

Klick-Ereignisse liefern in der Regel viel mehr Informationen, also können wir diesen Satz mit mehr Beschreibung erweitern:

The customer with IP 111.11.1111 clicked on product 12345 on 07/21/2023 at
11:20 am Eastern time.

Beachte, dass wir weder den Namen des Kunden oder des Produkts kennen, noch wissen wir, wo der Kunde wohnt oder wie alt er ist. Wir kennen auch nicht die Art des Produkts oder seine Farbe. Wir müssen das Clickstream-Ereignis mit Kunden- und Produktinformationen anreichern, bevor wir es zur Analyse bereitstellen.

Eine Frage, die du dir stellen könntest, ist: "Warum kann das Klickereignis nicht auch in der Datenbank gespeichert werden?" Das ist eine berechtigte Frage. Warum nicht die WAL nutzen, um die Klickereignisse zusammen mit den Entitäten zu lesen? Ein wichtiger Grund ist, dass der OLTP-Datenbank der Platz ausgehen könnte. Wenn du dir überlegst, wie oft ein Kunde in einer Anwendung auf Artikel klickt, wäre es nicht sinnvoll, all diese Daten in einer OLTP-Datenbank zu speichern. Entitäten ändern sich zwar sehr langsam, können aber gelöscht oder aktualisiert werden. Im Gegensatz dazu sind Klickereignisse unveränderlich und würden nur in eine Tabelle eingefügt werden. Dieses Muster wird auch als Append-Only bezeichnet. Klickereignisse lassen sich besser mit einem Microservice erfassen, der direkt in eine Streaming-Plattform schreibt.

Ein weiterer Unterschied ist, dass das Aktionsereignis angereichert wird und die Entitätsereignisse zum Anreichern verwendet werden. Die Kenntnis der Unterschiede zwischen Aktionsereignissen und Entitätsänderungsereignissen wird im Laufe dieses Buches von Bedeutung sein. Beide Typen werden unterschiedlich behandelt, wenn sie durch die Streaming Data Pipeline fließen, bis sie dem Endnutzer zur Verfügung gestellt werden.

Anreicherung des Kontextes

Alle Formen des analytischen Konsums benötigen einen Kontext, in dem das Ereignis stattgefunden hat. Das Klick-Ereignis enthält, wie bereits erwähnt, nur die mit dem Klick verbundenen Informationen, aber weder die Kunden- noch die Produktinformationen. Normalerweise sind die Informationen über die Entitäten zum Zeitpunkt des Klickereignisses nicht verfügbar. Wäre dies der Fall, wäre das Sammeln und Anreichern von Clickstream-Daten in der Anwendung aufgrund der Größe der Daten und der damit verbundenen Latenz nicht wirtschaftlich oder skalierbar.

Der bessere Weg, das Klick-Ereignis anzureichern, ist, es im Anschluss an eine Echtzeit-Datenpipeline durchzuführen. Mit diesen zusätzlichen Informationen lassen sich fundiertere Entscheidungen treffen. Wenn der Kunde z. B. grüne Hemden mag und ein Mann in den 20ern ist, kann er mit diesen Informationen intelligentere Entscheidungen treffen und die Anwendung personalisierter gestalten.

In unserem Anwendungsfall ist das Klickereignis mit zwei anderen Entitäten in der Geschäftsdomäne verbunden: dem Kunden und dem angeklickten Produkt. Wenn wir diese Details der Entitäten mit dem Klick-Ereignis kombinieren, entsteht ein aussagekräftigerer Kontext, der für Echtzeitanalysen benötigt wird. Eine aussagekräftige Analyse kann uns mehr über das Ereignis verraten und uns helfen, schnell auf Probleme zu reagieren, wie z. B. die Entscheidung, den Bestand an grünen Herrenhemden zu erhöhen.

Wir wissen, dass Entitäten, die zur Domäne der Anwendung gehören, in der OLTP-Datenbank existieren. Wir wissen auch, dass Änderungen an diesen Entitäten in den WAL geschrieben werden. Aber wir haben noch nicht darüber gesprochen, wie die Ereignisse im WAL zu einem Thema in einer Streaming-Plattform werden, wo andere Systeme Änderungsereignisse konsumieren und ihr Replikat der Entitäten in der Anwendung erstellen können. Das Replikat ermöglicht die Anreicherung des Klick-Ereignisses mit Produkt- und Kundeninformationen in einem nachgeschalteten Stream-Prozessor. Der Prozess der Erstellung dieses Replikats wird als Änderungsdatenerfassung bezeichnet.

Datenerfassung ändern

Change data capture (CDC) ist eine Technik, die in Datenbanken und Datenintegrationssystemen eingesetzt wird, um Datenänderungen in Echtzeit zu erfassen und zu verfolgen. Das Hauptziel der CDC ist es, alle Änderungstransaktionen (Einfügungen, Aktualisierungen oder Löschungen) in bestimmten Tabellen zu identifizieren und zu erfassen und die Änderungsereignisse für nachgelagerte Systeme oder Prozesse verfügbar zu machen.

Wenn du CDC durchführst, kannst du entweder einen Stream von ausgeführten Transaktionen abonnieren oder einen Snapshot aufnehmen. Snapshots sind keine Änderungsereignisse, wie du sie im WAL sehen würdest. In der Datenbankterminologie bezeichnet ein Snapshot eine Kopie einer Datenbank (oder einer Tabelle in einer Datenbank), die zu einem bestimmten Zeitpunkt aufgenommen wurde, so wie man einen Schnappschuss mit einer Kamera macht. Streams aus Datenbanken sind wie komprimierte Videos, bei denen jedes Einzelbild des Videos kein Bild (oder Schnappschuss) ist, sondern sich die Pixel von einem Bild zum nächsten ändern.

Hinweis

Die Art von Video, bei der nur die Änderungen zwischen den einzelnen Bildern gespeichert werden, um Rechenzeit zu sparen, wird delta encoding genannt. Delta-Encoding ist eine Videokomprimierungstechnik, bei der nur die Unterschiede zwischen aufeinanderfolgenden Bildern gespeichert werden. Dadurch kann die Größe der Videodatei erheblich reduziert werden, ohne dass die ursprüngliche Videoqualität verloren geht.

CDC kann auf verschiedene Weise umgesetzt werden:

Dem WAL zuhören

Das ist der Ansatz, den wir in diesem Kapitel besprochen haben, und die bevorzugte Methode, um Änderungen in einer Datenbank zu erfassen. Sie erfolgt in Echtzeit und natürlich im Streaming-Verfahren.

Hinweis

Der WAL-Ansatz zur Erfassung von Änderungstransaktionen wird typischerweise von relationalen OLTP-Datenbanken wie PostgreSQL und MySQL verwendet. Wir sprechen über diesen Ansatz, weil er den Konstrukten ähnelt, die Streams in Streaming-Plattformen aufzeichnen. Einige NoSQL-Transaktionsdatenbanken verfolgen diesen Ansatz nicht, sondern haben einen anderen Mechanismus, um Änderungen zu erfassen.

Schnappschüsse vergleichen

Dabei wird ein Snapshot einer Tabelle erstellt und mit einem früheren Snapshot verglichen, um Änderungen herauszufiltern. Dieser Vorgang kann prozessintensiv sein, vor allem wenn die Tabelle groß ist. Außerdem ist dieser Ansatz nicht wirklich echtzeitfähig. Snapshots werden in Intervallen erstellt. Änderungen, die zwischen den Intervallen stattfinden, würden verloren gehen. Verdächtige Änderungen und Rückgängigmachungen können manchmal unentdeckt bleiben.

Vergleich der Zeitstempel von Aktualisierungen

Dieser Ansatz speichert den Zeitstempel des letzten Änderungsstapels und filtert nach Datensätzen mit Aktualisierungszeitstempeln, die nach diesem Zeitpunkt liegen. Dieser Ansatz erfordert eine Aktualisierungsspalte in der Tabelle, die jedes Mal aktualisiert werden muss, wenn der Datensatz geändert wird. Auch dieser Ansatz ist nicht in Echtzeit.

Zum Glück haben die meisten OLTP-Datenbanken eine Möglichkeit, ihre WAL zu lesen. Einige OLTP-Datenbanken bieten auch native Unterstützung für die Übermittlung von Ereignissen an Streaming-Plattformen oder andere Systeme. Zum Beispiel bietet CockroachDB eine Möglichkeit, einen Change Feed von sich selbst zu erstellen:

  • Kafka

  • Google Cloud Pub/Sub

  • Cloud-Speicherung (Amazon S3, Google Cloud Storage, Azure Storage)

  • Webhook

Dadurch wird vermieden, dass ein Client den WAL in CockroachDB abonnieren muss. Stattdessen sendet CockroachDB Änderungsereignisse direkt an Kafka (siehe Beispiel 1-2). Dies ist ein bevorzugtes Muster, da es die architektonische Komplexität der Streaming Data Pipeline deutlich reduziert.

Beispiel 1-2. Erstellen eines Change Feeds von CockroachDB zu Kafka
CREATE CHANGEFEED FOR TABLE customer, product INTO 'kafka://localhost:9092';

Diese Funktion in OLTP-Datenbanken zu haben, bringt sie grundsätzlich näher an Streaming-Datenbanken heran. Wir werden in Kapitel 5 über Streaming-Datenbanken sprechen.

Warnung

Selbst wenn du Martin Kleppmann wärst, sind die Kapitel 1 bis 4 eine wichtige Lektüre vor Kapitel 5. Bitte überspringe sie nicht, denn sie liefern grundlegende Informationen für die Einführung von Streaming-Datenbanken in Kapitel 5.

Wie bereits erwähnt, reduziert dieser Push-Mechanismus die Komplexität der Architektur. Andere OLTP-Datenbanken, die diese Funktion nicht haben, benötigen zusätzliche Komponenten, die Konnektoren genannt werden, um Daten zu extrahieren und sie in einem Topic in einer Streaming-Plattform zu veröffentlichen.

Steckverbinder

Beim Streaming unterscheiden wir zwei Haupttypen von Konnektoren:

Quelle Anschlüsse

Quellkonnektoren lesen Daten aus einem Datenquellensystem (z. B. einer Datenbank) und stellen diese Daten als Ereignisstrom zur Verfügung.

Sinkende Anschlüsse

Sink-Konnektoren konsumieren Daten aus einem Ereignisstrom und schreiben diese Daten in ein Sink-System (wieder eine Datenbank oder ein Data Warehouse, einen Data Lake usw.).

Die beiden Arten von Konnektoren sind in Abbildung 1-8 dargestellt. In den meisten Fällen wandeln Quellkonnektoren entweder ruhende Daten in Streaming-Daten (auch Daten in Bewegung genannt) um, während Senkenkonnektoren Streaming-Daten in ruhende Daten umwandeln.

][alt
Abbildung 1-8. Quellenanschlüsse (oben) und Senkenanschlüsse (unten)

Mit Daten im Ruhezustand meinen wir, dass die Daten in einer Datenbank oder einem Dateisystem liegen und sich nicht bewegen. Daten im Ruhezustand werden in der Regel mit Batching- oder Microbatching-Techniken verarbeitet.4 Ein Datensatz, der von einem Quellsystem zu einem anderen gestapelt wird, hat einen Anfang und ein Ende. Die Anwendungen, die gestapelte Daten verarbeiten, können mit einem Zeitplannungsprogramm wie cron gestartet werden, und die Datenverarbeitung endet, wenn der Datensatz endet.

Das ist das Gegenteil von Streaming, also Daten in Bewegung. Daten in Bewegung bedeutet, dass es weder einen Anfang noch ein Ende für die Daten gibt. Anwendungen, die Streaming-Daten verarbeiten, sind immer in Betrieb und warten darauf, dass neue Daten im Stream ankommen.

Jetzt wollen wir uns ansehen, wie Source- und Sink-Konnektoren implementiert werden können.

Connector Middleware

Connector Middleware-Lösungen wie Kafka Connect, Meroxa, Striim oder StreamSets bieten bereits von Haus aus eine große Anzahl von Konnektoren und sind oft erweiterbar, um weitere Quellen und Senken zu bedienen. Connector-Middlewares bieten außerdem horizontale Skalierung, Überwachung und andere erforderliche Funktionen, insbesondere für den Produktionseinsatz.

Kafka Connect ist Teil des Apache Kafka-Projekts. Es handelt sich um einen verteilten Cluster, in dem Kafka-Konnektoren parallel eingesetzt werden. Diese Art des Einsatzes führt zu einer komplexen Streaming-Architektur. Diese Cluster sind sperrig und ihre Wartung ist mühsam.

Wenn du eine große Anzahl von Datenquellen und -senken hast, werden diese Cluster oft kostspielig und verbrauchen eine Menge Ressourcen. Die Delegation dieser Integration wird besser gelöst, indem die Konnektoren in die Systeme selbst eingebettet werden.

Eingebettet

Eine wachsende Zahl von Datenbanken bietet eingebettete Verbindungen zu Streaming-Plattformen. Wie wir bereits erwähnt haben, ist CockroachDB ein Beispiel dafür. Eine noch größere Anzahl von Datenbanken hat eingebettete Konnektoren implementiert, d. h. sie können selbst Daten aus dem Ereignisstrom abrufen. Beispiele sind Apache Druid, Apache Pinot, ClickHouse, StarRocks, Apache Doris und Rockset.

Wie wir bereits gesagt haben, kommen Datenbanken, die die Integration in Streaming-Plattformen lösen, dem Ziel näher, Streaming-Datenbanken zu werden. Wenn du Datenbanken die Fähigkeit gibst, Daten in Streaming-Plattformen zu ziehen und zu pushen, wird Streaming ganz natürlich zu einem Bürger erster Klasse in der Datenbank.

Sonderanfertigungen

Konnektoren können individuell erstellt werden, zum Beispiel durch die Implementierung eines speziellen Microservices. Der Vorteil dieses Ansatzes ist seine Flexibilität; der Nachteil ist eindeutig die Notwendigkeit, "das Rad neu zu erfinden" - es macht oft keinen Sinn, Konnektoren von Grund auf zu implementieren, vor allem angesichts der Vielzahl bestehender leistungsfähiger und skalierbarer Open source-Konnektoren (z. B. die Debezium source-Konnektoren für die Kafka Connect Middleware).

In Abbildung 1-9 haben wir die drei Arten der Implementierung von Konnektoren dargestellt (die Abbildung zeigt der Einfachheit halber nur die Quellkonnektoren; die entsprechenden Implementierungen der Sinkkonnektoren wären einfach ein Spiegelbild dieser Abbildung).

][alt
Abbildung 1-9. Möglichkeiten der Implementierung von Konnektoren über eine Konnektor-Middleware, einen integrierten Konnektor oder einen selbst erstellten Konnektor
Hinweis

Im weiteren Verlauf dieses Buches werden wir uns nicht mehr mit der eigentlichen Implementierung der Konnektoren befassen. Wenn wir von einem "Konnektor" sprechen, kann es sich dabei um einen Konnektor handeln, der auf einer Konnektor-Middleware basiert, einen eingebauten Konnektor oder einen selbst erstellten.

Zurück zu unserem Anwendungsbeispiel. Hier wollen wir Klickereignisse mit Produkt- und Kundeninformationen anreichern. Höchstwahrscheinlich befinden sich diese Daten in einer Transaktionsdatenbank oder einer Online Transactional Processing (OLTP) Datenbank. Um diese Daten als Ereignisstrom verfügbar zu machen, müssen wir einen Quellkonnektor für diese Datenbank verwenden.

Hinweis

Eine OLTP-Datenbank wird auch als operative Datenbank bezeichnet und bezeichnet einen Datenbanktyp, der für ein hohes Transaktionsvolumen ausgelegt ist. OLTP-Datenbanken sind so konzipiert, dass sie einen schnellen Datenzugriff und schnelle Aktualisierungen ermöglichen, was für Anwendungen wichtig ist, die Daten in Echtzeit verarbeiten müssen.

In Abbildung 1-10 kannst du sehen, dass die Produkt- und Kundeninformationen in einer OLTP-Datenbank gespeichert sind. Zwei Datenbank-Quellkonnektoren lesen aus dieser Datenbank und schreiben sie in Themen ("Produktthema" und "Kundenthema"). Die Klickereignisse werden in das Thema "Klickereignis " geschrieben.

][alt
Abbildung 1-10. Kunden- und Produktdaten in der Datenbank

Zusammenfassung

In diesem Kapitel haben wir einige grundlegende Streaming-Konzepte vorgestellt, indem wir Martin Kleppmann und seinen Ansatz, die Datenbank von innen nach außen zu drehen, vorgestellt haben. Dabei haben wir zwei Merkmale identifiziert, die die Grundlage für Streaming und Stream Processing bilden: die Datenbank WAL und die materialisierte Ansicht.

Wir haben gelernt, dass die Themen in Streaming-Plattformen externalisierte Datenbank-WALs sind, die andere Systeme abonnieren können. Diese anderen Systeme können dann Replikate von Tabellen aus der Quelldatenbank erstellen, z. B. mithilfe von CDC (oder anderen Formen von Konnektoren), und ihre Verarbeitung der Echtzeitdaten durchführen.

Im nächsten Kapitel fahren wir mit dem Clickstream-Anwendungsbeispiel fort und bringen es zum nächsten Schritt - der Streamverarbeitungsplattform, auf der die Anreicherung stattfinden wird.

1 Neben den beschriebenen Wiederherstellungsalgorithmen (Rollforward/Replay) gibt es noch andere Arten von Wiederherstellungsalgorithmen. Änderungen an den aktuellen Daten könnten auch vor COMMIT vorgenommen werden (vorausgesetzt, die WAL enthält den alten Wert), und nicht bestätigte Transaktionen könnten dann zurückgerollt werden.

2 Vorgänge können sich über mehrere Datensätze erstrecken. In diesem Fall entspricht der Schlüssel für die Aufteilung der Daten auf die Partitionen nicht direkt dem Primärschlüssel in der Quelldatenbank.

3 Der Einfachheit halber enthält unsere Transaktion hier nur einen Datensatz.

4 Es ist umstritten, ob Microbatching tatsächlich näher an Streaming oder Batch ist.

Get Streaming-Datenbanken now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.