Introduction à KafkaStreams en Java

Introduction à KafkaStreams en Java

1. Vue d'ensemble

Dans cet article, nous allons examiner lesKafkaStreams library.

KafkaStreams est conçu par les créateurs d'Apache Kafka. L'objectif principal de ce logiciel est de permettre aux programmeurs de créer des applications de streaming efficaces en temps réel qui pourraient fonctionner comme des microservices.

KafkaStreams nous permet de consommer à partir de sujets Kafka, d'analyser ou de transformer des données, et potentiellement de les envoyer vers un autre sujet Kafka.

Pour démontrerKafkaStreams,, nous allons créer une application simple qui lit les phrases d'un sujet, compte les occurrences de mots et imprime le nombre par mot.

Il est important de noter que la bibliothèqueKafkaStreams n’est pas réactive et ne prend pas en charge les opérations asynchrones et la gestion de la contre-pression.

2. Dépendance Maven

Pour commencer à écrire la logique de traitement de flux en utilisantKafkaStreams,, nous devons ajouter une dépendance àkafka-streams etkafka-clients:


    org.apache.kafka
    kafka-streams
    1.0.0


    org.apache.kafka
    kafka-clients
    1.0.0

Nous devons également installer et démarrer Apache Kafka car nous allons utiliser un sujet Kafka. Cette rubrique sera la source de données pour notre travail de diffusion en continu.

Nous pouvons télécharger Kafka et d'autres dépendances requises à partir dethe official website.

3. Configuration de l'entrée KafkaStreams

La première chose que nous allons faire est la définition du sujet Kafka d'entrée.

Nous pouvons utiliser l'outilConfluent que nous avons téléchargé - il contient un serveur Kafka. Il contient également leskafka-console-producer que nous pouvons utiliser pour publier des messages sur Kafka.

Pour commencer, exécutons notre cluster Kafka:

./confluent start

Une fois Kafka démarré, nous pouvons définir notre source de données et le nom de notre application en utilisantAPPLICATION_ID_CONFIG:

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

Un paramètre de configuration crucial est leBOOTSTRAP_SERVER_CONFIG..C'est l'URL de notre instance Kafka locale que nous venons de démarrer:

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

Ensuite, nous devons transmettre le type de la clé et la valeur des messages qui seront consommés à partir deinputTopic:

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.

Dans notre test, nous utilisons un système de fichiers local:

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

4. Création d'une topologie de streaming

Une fois que nous avons défini notre sujet d'entrée, nous pouvons créer une topologie de streaming - c'est-à-dire une définition de la manière dont les événements doivent être traités et transformés.

Dans notre exemple, nous souhaitons implémenter un compteur de mots. Pour chaque phrase envoyée àinputTopic,, nous voulons la diviser en mots et calculer l'occurrence de chaque mot.

Nous pouvons utiliser une instance de la classeKStreamsBuilder pour commencer à construire notre topologie:

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();

Pour implémenter le nombre de mots, nous devons tout d'abord diviser les valeurs à l'aide de l'expression régulière.

La méthode split renvoie un tableau. Nous utilisons lesflatMapValues() pour l'aplatir. Sinon, nous nous retrouverions avec une liste de tableaux et il ne serait pas pratique d’écrire du code en utilisant une telle structure.

Enfin, nous agrégons les valeurs de chaque mot et appelons lescount() qui calculeront les occurrences d'un mot spécifique.

5. Gestion des résultats

Nous avons déjà calculé le nombre de mots de nos messages d'entrée. Now let’s print the results on the standard output using the foreach() method:

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

En production, ce travail de diffusion en continu peut souvent publier le résultat dans un autre sujet Kafka.

Nous pourrions le faire en utilisant lesto() method:

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

La classeSerde nous donne des sérialiseurs préconfigurés pour les types Java qui seront utilisés pour sérialiser des objets dans un tableau d'octets. Le tableau d'octets sera ensuite envoyé au sujet Kafka.

Nous utilisonsString comme clé de notre sujet etLong comme valeur du nombre réel. La méthodeto() sauvegardera les données résultantes dansoutputTopic.

6. Démarrage de la tâche KafkaStream

Jusqu'à présent, nous avons construit une topologie pouvant être exécutée. Cependant, le travail n’a pas encore commencé.

Nous devons démarrer notre travail explicitement en appelant la méthodestart() sur l'instanceKafkaStreams:

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

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

Notez que nous attendons 30 secondes que le travail soit terminé. Dans un scénario réel, ce travail serait exécuté tout le temps et traiterait les événements de Kafka à leur arrivée.

Nous pouvons tester notre travail en publiant quelques événements sur notre sujet Kafka.

Commençons unkafka-console-producer et envoyons manuellement certains événements à nosinputTopic:

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

De cette façon, nous avons publié deux événements à Kafka. Notre application utilisera ces événements et imprimera la sortie suivante:

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

Nous pouvons voir que lorsque le premier message est arrivé, le motpony n'est apparu qu'une seule fois. Mais lorsque nous avons envoyé le deuxième message, le motpony s'est produit pour la deuxième impression: «word: pony → 2″.

6. Conclusion

Cet article explique comment créer une application de traitement de flux principale à l'aide d'Apache Kafka comme source de données et de la bibliothèqueKafkaStreams comme bibliothèque de traitement de flux.

Tous ces exemples et extraits de code peuvent être trouvés dans leGitHub project - il s'agit d'un projet Maven, il devrait donc être facile à importer et à exécuter tel quel.