Kafka Streams

Inhalt

Quickstart Kafka Streams - Ohne Hürden in die Echtzeitverarbeitung

Kafka Streams ist eine Open-Source Java Bibliothek, die einen entscheidenden Teil im Kafka Ökosystem darstellt. Sie ermöglicht die Verarbeitung und Analyse von Datenströmen in Echtzeit auf der Grundlage des Apache Kafka Projekts, einer verteilten Event-Streaming-Plattform. Mit Kafka Streams können Entwickler komplexe Stream-Verarbeitungslogik erstellen, ohne auf externe Frameworks oder Bibliotheken angewiesen zu sein.

In vielen Schulungen und Präsentationen taucht Kafka Streams nur als Icon auf, ohne auf die Details der Bibliothek einzugehen. Weiterhin ist für die Nutzung und Pilotierung von Kafka Streams immer ein Kafka Cluster, sowie eine kompilierte Java Applikation erforderlich. Diese Umstände halten viele potenzielle Nutzer davon ab, den richtigen Einstieg in die Technologie zu finden. Deshalb haben wir eine ganzheitliche Demo entwickelt, die mit wenigen Klicks ein Kafka Cluster, die benötigten Kafka Topics und eine Kafka Streams Anwendung startet. Dieser Artikel behandelt die Grundlagen von Kafka Streams, sowie die Schritte, wie Sie die Demo innerhalb von 10 Minuten zum Fliegen bringen.

Kafka Quick Demo

Warum gibt es Kafka Streams

Typische Apache Kafka Projekte starten damit, dass Daten von verschiedenen Datenquellen in die Plattform gestreamt werden. Bis zu diesem Punkt findet eine Echtzeitverarbeitung statt. Da Kafka keine Datenbank, sondern ein Commit Log ist, existiert keine Möglichkeit direkt über die Plattform Queries auszuführen, wie es beispielsweise bei einer SQL Datenbank möglich wäre. Jegliche Art von Verarbeitung der Daten mit klassischen Batch- oder Microbatchverfahren würde außerdem die Latenz der Verarbeitung stark erhöhen und das Paradigma der Echtzeitverarbeitung brechen. Dafür wird eine Applikation benötigt, die „Event-At-a-Time“ Verarbeitung umsetzt und wieder auf die Plattform schreibt. Dabei sollten Transformationen wie Aggregationen, Joins und Windowing implementiert werden. Kafka Streams ist diese Anwendung und löst dabei nativ viele Probleme.

Schlüsselfeatures von Kafka Streams

Applikation
ist lediglich ein JAR File, dass dann auf beliebigen Servern, In Kubernetes oder lokal ausgeführt werden kann.
Persistieren von Zustand und Metadaten in Kafka Topics
Jede Kafka Streams App wird mit einer eindeutigen Application ID gestartet. Zu dieser ID legt die App Topics in Kafka an. Bei einem Absturz oder Neustart kann so ohne Datenverlust weiterverarbeitet werden.
Skalierbarkeit und Hochverfügbarkeit

Wird nur eine Instanz der Java App ausgeführt, besteht das Risiko, dass hier ein Bottleneck in der Verarbeitung entsteht. Des Weiteren würde bei einem Absturz der Applikation die Verarbeitung stillstehen.


Es ist möglich beliebig viele Instanzen der App mit der gleichen Application ID und Applikationslogik zu starten. Diese Instanzen verarbeiten nun die Daten parallelisiert, da jede Instanz automatisiert nur bestimmte Topic Partitionen übernimmt. Fällt eine der Instanzen aus, übernehmen die anderen Instanzen diese Partitionen. Das ist möglich durch die interne Koordination über das Kafka Cluster. Dieser Umstand erlaubt auch eine hohe Flexibilität, um auf Lastspitzen zu reagieren, sowie das System zu reduzieren, um ggf. Cloudkosten zu sparen. Es ist lediglich sicherzustellen, dass die zu verarbeitenden Topics mindestens so viele Partitionen haben, wie Instanzen existieren.

Topic zu Topic Verarbeitung
Kafka Streams verarbeitet immer ein Quelltopic und schreibt kontinuierlich „Event-At-a-Time“ in ein Zieltopic. Dadurch ist eine tatsächliche Echtzeitverarbeitung möglich.
Stateful Processing
Zwischenergebnisse und aktuelle Zustände von Aggregationen speichert Kafka Streams in einer RocksDB. Dabei legt jede App Instanz ihre eigene RocksDB auf dem Filesystem an und verwaltet diese eigenständig. Die dort gespeicherten Werte können durch Neuberechnung immer wieder hergestellt werden. RocksDB stellt lediglich einen internen Zwischenspeicher dar und ist nicht für externe Zugriffe gedacht.
Stream-Table Duality
Verarbeitungen, die typischerweise auf Tabellen durchgeführt werden, implementiert Kafka Streams adaptiert auf Streams. Dieses Konzept ist am besten im folgenden Beispiel nachzuvollziehen.

Aufsetzen des Quickstarts

Damit Sie direkt nachvollziehen können, wie eine Kafka Streams Applikation arbeitet, empfehlen wir nun die Quickstart Umgebung aufzusetzen (Aufwand von etwa 10 Minuten). Alternativ können Sie auch nur das nachfolgende Beispiel als Consumer verarbeiten.

Docker Installation

Für die Ausführung des Quickstarts benötigen Sie lediglich eine laufende Docker Installation mit Docker-Compose. Für Windows können Sie zum Beispiel Docker Desktop installieren (https://docs.docker.com/desktop/install/windows-install/). Führen Sie danach Docker Desktop aus. Sie sollten folgendes Fenster sehen.

Öffnen Sie nun eine Shell (zum Beispiel Powershell) und verifizieren Sie die Installation:

				
					docker-compose --version 

docker --version 
				
			

Aufsetzen von Kafka

Laden Sie sich nun die docker-compose Datei hier herunter und speichern Sie es auf ihrem Rechner.

Navigieren Sie in der Shell zu dem Ordner, in dem sich die Datei auf ihrem Rechner befindet.

 

Starten Sie das Cluster

				
					docker-compose up -d
				
			
Laden Sie sich das Kafka Streams Repository hier herunter und navigieren Sie in den Ordner, in dem sich das Dockerfile befindet. Erstellen Sie nun das Image.
				
					docker build -t streamsdemo .

#Prüfen Sie, ob das Image existiert#

docker images

#Führen Sie das Image aus#

docker run --network host --name=streamsdemo-container streamsdemo

				
			

Tiefer einsteigen? Wir bieten einen Apache Kafka Streams Workshop an. 

Wordcount mit Kafka Streams

Durch das Ausführen des „streamsdemo“ Containers, wird sowohl ein Producer, ein Consumer und eine Kafka Streams Applikation gestartet. In den Logs des Containers wird dann geloggt, welche Messages in das Quell Topic geschrieben werden, sowie, welche aggregierten Messages im Ziel Topic landen.

Etwa 10-15 Sekunden nach dem Starten des Containers, sieht man im Log jeweils die zufällig generierten Messages. Im Beispiel unter „Producing Message“

Danach werden die neuen Messagen im output Topic angezeigt. Sprich, die Daten, die aus der Aggregation der Eingangsmessages berechnet wurden. Im Beispiel sieht man, dass für jede Frucht die in der Quellnachricht vorkommt, eine Nachricht im Zieltopic ankommt. Im ersten Fall sind es 3 verschiedene Früchte, daher 3 Nachrichten. Im zweiten Falls kommt „Cherry“ zweimal vor, daher sind es nur 2 Nachrichten. Die Nachrichten im Zieltopic enthalten immer die bisher gezählte Anzahl an Vorkommen eines Wortes – Wordcount. Dabei ist wichtig zu verstehen, dass hier keine Daten aktualisiert werden, sondern die Nachrichten immer hinten an das Topic angehängt wird. Das Zieltopic enthält nach diesem Beispiel 5 Nachrichten, das Quelltopic nur 2.

Sie können die Applikation belieb oft neustarten, bei jedem Neustart werden die Topics zurückgesetzt. Es werden so lange Daten generiert, bis der Container gestoppt wird.

Diese Kafka Streams Applikation arbeitet intern mit der Funktion „flatMapValues“. Da hier lediglich der Value der Quellnachricht verwendet und der Key ignoriert wird. Jede Nachricht wird über Leerzeichen in der Nachricht, in ein Array von Wörtern aufgespaltet. Nach diesen Wörtern wird dann gruppiert und die Anzahl der Vorkommen aufsummiert.

Neben dieser sehr einfachen Applikation können in Kafka Streams noch viele weitere Operationen durchgeführt werden. Dieser Artikel soll Ihnen vor allem die Möglichkeit geben, schnell einzusteigen und eine lauffähige Demo zu bekommen.

FAQ zu Kafka Streams: Technische Details für Experten

Was unterscheidet die KStream- und KTable-API in Kafka Streams?
KStream repräsentiert einen Datenstrom von Schlüssel-Wert-Paaren, wobei jeder Datenpunkt als unabhängiges Ereignis betrachtet wird. KTable hingegen repräsentiert eine ständig aktualisierte Tabelle, wobei jeder Schlüssel nur einmal vorkommt und sein Wert über die Zeit aktualisiert werden kann.
Wie kann man die Zustandsspeicherung in Kafka Streams optimieren?
Man sollte RocksDB-Tuning in Betracht ziehen, die Anzahl der Standby-Replikas reduzieren und die commit.interval.ms erhöhen, um den I/O-Overhead zu minimieren.
Wie funktioniert die genaue Semantik der "exactly once" Verarbeitung in Kafka Streams?
Kafka Streams verwendet eine Kombination aus idempotenten Produzenten und Transaktions-APIs. Dies stellt sicher, dass Daten weder doppelt produziert noch verarbeitet werden und sorgt für genau einmalige Verarbeitungssemantik.
Welche Performance-Optimierungen gibt es für Kafka Streams?
Wie kann man eine individuelle Timestamp-Extraktion in Kafka Streams implementieren?
Man kann das TimestampExtractor-Interface implementieren und die Methode extract überschreiben, um eine benutzerdefinierte Logik zur Timestamp-Extraktion bereitzustellen.
Wie behandelt Kafka Streams Fensteroperationen und Punktionsmechanismen?
Kafka Streams unterstützt sowohl Tumbling Windows als auch Sliding Windows. Mit dem Punktionsmechanismus kann man Aktionen in regelmäßigen Intervallen ausführen, um beispielsweise alte Daten zu löschen oder Ressourcen freizugeben.
Gibt es spezielle Empfehlungen für das Deployment von Kafka Streams in Kubernetes?
Kafka Streams bietet einen ProductionExceptionHandler und DeserializationExceptionHandler an. Bei einem Fehler kann man wählen, ob der Record übersprungen, der Stream beendet oder der Fehler weitergegeben werden soll.
Wie behandelt Kafka Streams Fehler und Ausnahmesituationen?
Kafka Streams bietet einen ProductionExceptionHandler und DeserializationExceptionHandler an. Bei einem Fehler kann man wählen, ob der Record übersprungen, der Stream beendet oder der Fehler weitergegeben werden soll.