Einführung in KafkaStreams in Java

Einführung in KafkaStreams in Java

1. Überblick

In diesem Artikel werden dieKafkaStreams library betrachtet.

KafkaStreams wurde von den Entwicklern von Apache Kafka entwickelt.. Das Hauptziel dieser Software besteht darin, Programmierern die Erstellung effizienter Streaming-Anwendungen in Echtzeit zu ermöglichen, die als Microservices fungieren können.

KafkaStreams ermöglicht es uns, Kafka-Themen zu verwenden, Daten zu analysieren oder zu transformieren und sie möglicherweise an ein anderes Kafka-Thema zu senden.

UmKafkaStreams, zu demonstrieren, erstellen wir eine einfache Anwendung, die Sätze aus einem Thema liest, das Auftreten von Wörtern zählt und die Anzahl pro Wort druckt.

Es ist wichtig zu beachten, dass die Bibliothek vonKafkaStreamsnicht reaktiv ist und keine Unterstützung für asynchrone Vorgänge und die Behandlung von Gegendruck bietet.

2. Maven-Abhängigkeit

Um mit dem Schreiben der Stream-Verarbeitungslogik mitKafkaStreams, zu beginnen, müssen wirkafka-streams undkafka-clients eine Abhängigkeit hinzufügen:


    org.apache.kafka
    kafka-streams
    1.0.0


    org.apache.kafka
    kafka-clients
    1.0.0

Außerdem muss Apache Kafka installiert und gestartet werden, da wir ein Kafka-Thema verwenden. Dieses Thema ist die Datenquelle für unseren Streaming-Auftrag.

Wir können Kafka und andere erforderliche Abhängigkeiten vonthe official website herunterladen.

3. Konfigurieren der KafkaStreams-Eingabe

Das erste, was wir tun werden, ist die Definition des Eingabe-Kafka-Themas.

Wir können das von uns heruntergeladene ToolConfluentverwenden - es enthält einen Kafka-Server. Es enthält auch diekafka-console-producer, mit denen wir Nachrichten an Kafka veröffentlichen können.

Lassen Sie uns zunächst unseren Kafka-Cluster ausführen:

./confluent start

Sobald Kafka startet, können wir unsere Datenquelle und den Namen unserer Anwendung mitAPPLICATION_ID_CONFIG definieren:

String inputTopic = "inputTopic";
Properties streamsConfiguration = new Properties();
streamsConfiguration.put(
  StreamsConfig.APPLICATION_ID_CONFIG,
  "wordcount-live-test");

Ein entscheidender Konfigurationsparameter istBOOTSTRAP_SERVER_CONFIG.. Dies ist die URL zu unserer lokalen Kafka-Instanz, die wir gerade gestartet haben:

private String bootstrapServers = "localhost:9092";
streamsConfiguration.put(
  StreamsConfig.BOOTSTRAP_SERVERS_CONFIG,
  bootstrapServers);

Als nächstes müssen wir den Typ des Schlüssels und den Wert der Nachrichten übergeben, die voninputTopic: verbraucht werden

streamsConfiguration.put(
  StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG,
  Serdes.String().getClass().getName());
streamsConfiguration.put(
  StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG,
  Serdes.String().getClass().getName());

Stream processing is often stateful. When we want to save intermediate results, we need to specify the STATE_DIR_CONFIG parameter.

In unserem Test verwenden wir ein lokales Dateisystem:

streamsConfiguration.put(
  StreamsConfig.STATE_DIR_CONFIG,
  TestUtils.tempDirectory().getAbsolutePath());

4. Erstellen einer Streaming-Topologie

Sobald wir unser Eingabethema definiert haben, können wir eine Streaming-Topologie erstellen. Dies ist eine Definition, wie Ereignisse behandelt und transformiert werden sollen.

In unserem Beispiel möchten wir einen Wortzähler implementieren. Für jeden Satz, der aninputTopic, gesendet wird, möchten wir ihn in Wörter aufteilen und das Auftreten jedes Wortes berechnen.

Wir können eine Instanz derKStreamsBuilder-Klasse verwenden, um mit der Erstellung unserer Topologie zu beginnen:

KStreamBuilder builder = new KStreamBuilder();
KStream textLines = builder.stream(inputTopic);
Pattern pattern = Pattern.compile("\\W+", Pattern.UNICODE_CHARACTER_CLASS);

KTable wordCounts = textLines
  .flatMapValues(value -> Arrays.asList(pattern.split(value.toLowerCase())))
  .groupBy((key, word) -> word)
  .count();

Um die Wortzahl zu implementieren, müssen wir zunächst die Werte mithilfe des regulären Ausdrucks aufteilen.

Die Aufteilungsmethode gibt ein Array zurück. Wir verwenden dieflatMapValues(), um sie zu reduzieren. Andernfalls erhalten wir eine Liste von Arrays, und es wäre unpraktisch, Code mit einer solchen Struktur zu schreiben.

Schließlich aggregieren wir die Werte für jedes Wort und rufen diecount() auf, die das Auftreten eines bestimmten Wortes berechnen.

5. Ergebnisse behandeln

Wir haben bereits die Wortanzahl unserer Eingabenachrichten berechnet. Now let’s print the results on the standard output using the foreach() method:

wordCounts
  .foreach((w, c) -> System.out.println("word: " + w + " -> " + c));

In der Produktion wird die Ausgabe häufig in einem anderen Kafka-Thema veröffentlicht.

Wir könnten dies mitto() method: tun

String outputTopic = "outputTopic";
Serde stringSerde = Serdes.String();
Serde longSerde = Serdes.Long();
wordCounts.to(stringSerde, longSerde, outputTopic);

Die KlasseSerde gibt uns vorkonfigurierte Serializer für Java-Typen, mit denen Objekte in ein Array von Bytes serialisiert werden. Das Array von Bytes wird dann an das Kafka-Thema gesendet.

Wir verwendenString als Schlüssel für unser Thema undLong als Wert für die tatsächliche Anzahl. Die Methodeto() speichert die resultierenden Daten inoutputTopic.

6. KafkaStream Job starten

Bis zu diesem Punkt haben wir eine Topologie erstellt, die ausgeführt werden kann. Der Job hat jedoch noch nicht begonnen.

Wir müssen unseren Job explizit starten, indem wir die Methodestart()für die InstanzKafkaStreamsaufrufen:

KafkaStreams streams = new KafkaStreams(builder, streamsConfiguration);
streams.start();

Thread.sleep(30000);
streams.close();

Beachten Sie, dass wir 30 Sekunden warten, bis der Auftrag abgeschlossen ist. In einem realen Szenario würde dieser Job die ganze Zeit ausgeführt und Ereignisse von Kafka verarbeiten, sobald sie eintreffen.

Wir können unseren Job testen, indem wir einige Veranstaltungen zu unserem Kafka-Thema veröffentlichen.

Beginnen wir mitkafka-console-producer und senden einige Ereignisse manuell an unsereinputTopic:

./kafka-console-producer --topic inputTopic --broker-list localhost:9092
>"this is a pony"
>"this is a horse and pony"

Auf diese Weise haben wir zwei Ereignisse für Kafka veröffentlicht. Unsere Anwendung verwendet diese Ereignisse und gibt die folgende Ausgabe aus:

word:  -> 1
word: this -> 1
word: is -> 1
word: a -> 1
word: pony -> 1
word:  -> 2
word: this -> 2
word: is -> 2
word: a -> 2
word: horse -> 1
word: and -> 1
word: pony -> 2

Wir können sehen, dass das Wortpony beim Eintreffen der ersten Nachricht nur einmal vorkam. Aber als wir die zweite Nachricht gesendet haben, wurde das Wortpony zum zweiten Mal gedruckt: „word: pony → 2″.

6. Fazit

In diesem Artikel wird erläutert, wie Sie eine primäre Stream-Verarbeitungsanwendung mit Apache Kafka als Datenquelle und derKafkaStreams-Bibliothek als Stream-Verarbeitungsbibliothek erstellen.

Alle diese Beispiele und Codefragmente finden Sie inGitHub project - dies ist ein Maven-Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.