Was ist Kafka Streams?
Kafka Streams ist eine Java (bzw. Scala) Bibliothek, die auf Apache Kafka (weiterhin Kafka genannt) aufsetzt und das Streaming von Daten in Echtzeit ermöglicht. Um Kafka Streams zu verstehen, braucht man daher einen kleinen Einblick in das Ökosystem von Kafka.
Im Kafka Ökosystem gibt es Bausteine, die klein starten und zu immer größeren Bausteinen zusammengesetzt werden können. Das kleinste Element ist ein sogenannter „Record“, der aus einem Pärchen von einem Schlüssel und einem Wert (Key-Value Pair) besteht. Diese Records werden in sogenannten Topics als Bytes gespeichert und persistiert. Um die Datenverarbeitung parallelisieren zu können, besteht ein Topic aus N verschiedenen Partitionen, wobei N eine konfigurierbare Zahl ist.
Zum Schreiben von Daten in ein Topic und zum Lesen von Daten aus einem Topic werden jeweils zwei Objekte benötigt: Zum einen werden beim Schreiben ein Serializer und ein Producer benutzt. Dabei wandelt der Serializer einen Record in seine Byte Repräsentation um. Zu anderen wird zum Lesen ein Deserializer und ein Consumer verwendet. Hier liest der Deserializer die Byte Repräsentation und konvertiert diese wieder in den Record. Weiterhin persistieren Producer die Records mit Hilfe der Serializer im Topic, während die Consumer diese auslesen und somit eine Weiterverarbeitung ermöglichen. Dabei ist es wichtig zu wissen, dass Daten, die von einem von M Konsumenten aus einem Topic gelesen werden, weiterhin für alle anderen Konsumenten zur Verfügung stehen (im Gegensatz zu einer Message Queue). Jede Kafka Streams Applikation besteht mindestens aus der Kombination von einem Consumer und einem Producer, die von der Java Bibliothek gehandhabt wird.
Zusätzlich kann eine Kafka Streams Applikation noch zusätzliche Bestandteile haben, unter anderem können das State Stores, in denen Daten in einer RocksDB vorgehalten werden können, Transformern, in denen Daten transformiert werden, oder anderen Bestandteilen sein. Dabei erlaubt der Einsatz von State Stores sogenannte stateful Operationen, da der letzte Stand eines Records im State Store abgelegt werden kann. Dadurch kann komplexere Logik implementiert werden als in stateless Operationen, wo nur Zugriff auf den aktuellen Stand eines Records möglich ist.
Kafka Streams und ihre Topologie
Wie die Einzelteile der Kafka Stream Applikation zusammenspielen, kann in Graphen, der „Topologie“, dargestellt werden. Eine schematische Darstellung von einer Topologie ist in Abbildung 1 zu sehen. In diesen Topologien können Daten sowohl in kontinuierlichen Streams, den KStreams, verarbeitet werden, als auch in Tabellen, den KTables, verarbeitet werden. Die zwei größten Vorteile von Kafka Streams gegenüber einem Consumer-Producer Paar in Apache Kafka sind, einerseits die Möglichkeit stateful Operationen mit Hilfe von State Stores durchführen zu können, andererseits, dass man sich bei der Entwicklung einer Kafka Streams Applikation fast ausschließlich auf die Datenverarbeitung konzentrieren kann und sich nicht um low-level Thematiken wie Parallelisierung, Fehlertoleranz und Skalierbarkeit kümmern muss.
Was ist überhaupt Streaming und was ist der Unterschied zu Batch Prozessen?
Sowohl Streaming als auch ein Batch Prozess beschreibt die automatisierte Verarbeitung von Daten als Bündelung von vielen Einzelschritten. Der größte Unterschied zwischen beiden Typen der Verarbeitung ist, wann und wie oft die Daten verarbeitet werden. Eines der Erkennungsmerkmale eines Batch Prozesses ist, dass es in regelmäßigen Abständen ausgeführt wird, wie zum Beispiel bei einer Tagesabschlussverarbeitung von Verkaufsdaten. Daher gibt es bei der Batch Verarbeitung immer einen klar definierten Startzeitpunkt und einen klar definierten Endzeitpunkt. Im Kontrast dazu steht das Streaming, bei dem Daten kontinuierlich verarbeitet werden, sobald diese zur Verfügung stehen. Da die Daten kontinuierlich verarbeitet den, ist es möglich in Echtzeit die Daten weiter zu verarbeiten. Das ist besonders interessant, in Situationen, in denen sich Daten oft und schnell ändern können, wie zum Beispiel bei ein GPS Empfänger, der jede Sekunde ausgelesen wird. Diese Daten können dann in Echtzeit zum Beispiel in einem Flugzeug benutzt werden, um zu überprüfen, dass man weiterhin auf dem richtigen Kurs ist. Der zweite typische Anwendungsfall entsteht dann, wenn Daten in (nahezu) Echtzeit Bereitgestellt werden müssen, beispielsweise auf einer grafischen Oberfläche. Müsste man in diesen beiden Fällen erst warten, bis die Daten in einem vordefinierten Zeitfenster verarbeitet werden, wäre dies sehr mühsam.
Beispiel für Unterschiede beim Streaming gegenüber Batch Prozessen
Während Streaming eine hervorragende Möglichkeit bietet, um Prozesse im Betrieb zu beschleunigen, ist es kein Selbstläufer. Das größte Risiko beim Verwenden von Streaming Prozessen ist es, einen solchen Prozess identisch zu behandeln wie einen Batch Prozess. In der Welt von Batch Prozessen muss man sich wenig Gedanken machen, wann und in welcher Reihenfolge Daten verschickt werden. Wenn man Daten aus zwei Quellsystemen in einem Join verarbeiten möchte, lädt man im Batch Prozess zunächst das erste Set von Daten in die erste Tabelle, dann das zweite Set in eine zweite Tabelle und führt dann den Join durch. Solange die Daten vor der Verarbeitung vorliegen, ist es beim Batch Prozess daher egal, wann die Daten geschickt werden. Im Gegensatz dazu, kann die Reihenfolge und der Zeitpunkt in einer Kafka Streams Applikation bei einem Join entscheidend sein. Dazu sollte erwähnt werden, dass es bei Kafka Streams verschiedene Kombinationsmöglichkeiten gibt. Je nach Datenlage kann es sinnvoll sein, zwei KStreams, zwei KTables oder einen KStream und einen KTable miteinander Joinen. Die Unterscheidung ist wichtig, da sich die Joins von der verschiedenen Objekte unterschiedlich verhalten. Welche Joins für die Kombinationen zur Verfügung stehen, ist in Abbildung 2 zu sehen.
Kafka Streams am Beispiel des Left Joins
Will man beispielsweise einen Left Join zwischen einem KStream und einem KTable durchführen, spielt die Reihenfolge der Events eine wichtige Rolle. Stellen wir uns vor, dass wir zwei Datensets in Echtzeit beziehen. Erstens durch einen KStream, genannt Views (als linker Anteil) und zweitens durch einen KTable, genannt Klicks (als rechter Anteil). Sobald ein Event in der View entsteht, wird der Join durchgeführt. Wenn die Daten wie in Abbildung 3 kommen, führt das dazu, dass die Ergebnisse des Left Joins zwischen einer Kafka Streams Applikation und einem Batch Prozess abweichen können. Im Beispiel vom Event „A“ in dem Daten für Views zum Zeitpunkt 0 und für Klicks zum Zeitpunkt 1 kommen, wird das Ergebnis für eine Kafka Streams Applikation nur den linken Anteil enthalten, während ein Batch Prozess sowohl den linken als auch den rechten Anteil beinhaltet hätte. Daher sind die Ergebnisse vom Streaming und vom Batch Prozess nur identisch, wenn der rechte Anteil zu erst oder nie kommt,
Zusammenfassung
Kafka Streams ist eine benutzerfreundliche high-level Java Bibliothek, mit der man Daten kontinuierlich und in Echtzeit verarbeitet. Damit ist Kafka Streams eines von vielen Beispielen für einen Streaming Prozess. In einer Kafka Streams Applikation werden Daten aus mindestens einem Topic gelesen, angereichert und letztlich in mindestens einem Topic geschrieben. Die Anreicherung kann dabei sowohl stateless als auch stateful mit einem State Store stattfinden. Streaming steht generell im Gegensatz zu Batch Verarbeitung von Daten, in der Daten an vordefinierten Zeitpunkten prozessiert werden. Daher ist es ein größse Risiko eine Kafka Streams Applikation so zu entwickeln wie einen Batch Prozess. Im Gegensatz zu Batch Prozessen, kann die nämlich Reihenfolge von Events einen großen Einfluss auf das Ergebnis haben.