Dans la conception de systèmes modernes, l’Architecture Orientée Événements (AOE) se concentre sur la création, la détection, l’utilisation et la réponse aux événements au sein d’un système. Les événements sont des occurrences significatives qui peuvent affecter le matériel ou le logiciel d’un système, comme les actions des utilisateurs, les changements d’état ou les mises à jour de données.

L’AOE permet à différentes parties d’une application d’interagir de manière découplée, leur permettant de communiquer par le biais d’événements plutôt que d’appels directs. Cette configuration permet aux composants de travailler de manière indépendante, de répondre aux événements de manière asynchrone et de s’adapter aux besoins commerciaux changeants sans reconfiguration majeure du système, favorisant ainsi l’agilité.

Les nouvelles et applications modernes s’appuient désormais fortement sur le traitement des données en temps réel et la réactivité. L’importance de l’AOE ne peut être surestimée car elle fournit le cadre qui soutient ces exigences. En utilisant la communication asynchrone et les interactions orientées événements, les systèmes peuvent gérer efficacement des volumes élevés de transactions et maintenir des performances sous des charges instables. Ces caractéristiques sont particulièrement appréciées dans des environnements où les changements sont très spontanés, tels que les plateformes de commerce électronique ou les applications IoT.

Certains composants clés de l’AOE incluent :

  • Sources d’Événements : Ce sont les producteurs qui génèrent des événements lorsque des actions significatives se produisent au sein du système. Des exemples incluent les interactions des utilisateurs ou les changements de données.

  • Écouteurs: Ce sont des entités qui s’abonnent à des événements spécifiques et réagissent lorsque ces événements se produisent. Les écouteurs permettent au système de réagir dynamiquement aux changements.

  • Gestionnaires: Ils sont responsables du traitement des événements une fois qu’ils sont détectés par les écouteurs, exécutant la logique métier ou les workflows nécessaires déclenchés par l’événement.

Dans cet article, vous apprendrez comment mettre en œuvre le traitement de données piloté par des événements en utilisant Traefik, Kafka et Docker.

Voici une application simple hébergée sur GitHub que vous pouvez exécuter rapidement pour avoir un aperçu de ce que vous allez construire aujourd’hui.

Table des matières

Voici ce que nous allons couvrir:

Commençons !

Prérequis

Avant de commencer :

  • Déployez une instance Ubuntu 24.04 avec au moins 4 Go de RAM et un minimum de 20 Go d’espace disque libre pour accueillir les images Docker, les conteneurs et les données Kafka.

  • Accédez à l’instance avec un utilisateur non-root disposant de privilèges sudo.

  • Mettez à jour l’index des paquets.

sudo apt update

Compréhension des technologies

Apache Kafka

Apache Kafka est une plateforme de streaming d’événements distribuée conçue pour les pipelines de données à haut débit et les applications de streaming en temps réel. Il sert de colonne vertébrale pour la mise en œuvre de l’EDA en gérant efficacement de gros volumes d’événements. Kafka utilise un modèle de publication-abonnement où les producteurs envoient des événements à des topics et les consommateurs s’abonnent à ces topics pour recevoir les événements.

Certaines des principales caractéristiques de Kafka incluent :

  • Débit élevé : Kafka est capable de gérer des millions d’événements par seconde avec une faible latence, ce qui le rend adapté aux applications à volume élevé.

  • Tolérance aux pannes: L’architecture distribuée de Kafka garantit la durabilité et la disponibilité des données même en cas de défaillance du serveur. Elle réplique les données sur plusieurs courtiers au sein d’une grappe.

  • Scalabilité: Kafka peut facilement s’étendre horizontalement en ajoutant plus de courtiers à la grappe ou des partitions aux sujets, répondant aux besoins croissants en données sans une reconfiguration significative.

Traefik

Traefik est un proxy inverse HTTP moderne et un équilibrage de charge conçu spécifiquement pour les architectures de microservices. Il découvre automatiquement les services en cours d’exécution dans votre infrastructure et dirige le trafic en conséquence. Traefik simplifie la gestion des microservices en offrant des capacités de routage dynamique basées sur les métadonnées du service.

Certaines des fonctionnalités clés de Traefik incluent :

  • Configuration dynamique : Traefik met à jour automatiquement sa configuration de routage lorsque des services sont ajoutés ou supprimés, éliminant ainsi l’intervention manuelle.

  • Équilibrage de Charge : Il répartit efficacement les requêtes entrantes sur plusieurs instances de service, améliorant ainsi les performances et la fiabilité.

  • Tableau de Bord Intégré : Traefik fournit un tableau de bord convivial pour surveiller le trafic et la santé des services en temps réel.

En utilisant Kafka et Traefik dans une architecture orientée événements, vous pouvez construire des systèmes réactifs qui gèrent efficacement le traitement des données en temps réel tout en maintenant une haute disponibilité et scalabilité.

Comment Configurer l’Environnement

Comment Installer Docker sur Ubuntu 24.04

  1. Installez les paquets requis.
sudo apt install ca-certificates curl gnupg lsb-release
  1. Ajoutez la clé GPG officielle de Docker.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  1. Ajoutez le dépôt Docker à vos sources APT.
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  1. Mettez à jour l’index des paquets à nouveau et installez Docker Engine avec le plugin Docker Compose.
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  1. Vérifiez pour confirmer l’installation.
sudo docker run hello-world

Sortie Attendue :

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:305243c734571da2d100c8c8b3c3167a098cab6049c9a5b066b6021a60fcb966
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

Comment Configurer Docker Compose

Docker Compose simplifie la gestion des applications multi-conteneurs, vous permettant de définir et d’exécuter des services dans un seul fichier.

  1. Créez un répertoire de projet
mkdir ~/kafka-traefik-setup && cd ~/kafka-traefik-setup
  1. Créez un fichier docker-compose.yml.
nano docker-compose.yml
  1. Ajoutez la configuration suivante au fichier pour définir vos services.
version: '3.8'

services:
  kafka:
    image: wurstmeister/kafka:latest
    ports:
      - "9092:9092"
    environment:
      KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9092,OUTSIDE://localhost:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
      KAFKA_LISTENERS: INSIDE://0.0.0.0:9092,OUTSIDE://0.0.0.0:9092
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181

  zookeeper:
    image: wurstmeister/zookeeper:latest
    ports:
      - "2181:2181"

  traefik:
    image: traefik:v2.9
    ports:
      - "80:80"       # Trafic HTTP
      - "8080:8080"   # Tableau de bord de Traefik (non sécurisé)
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

Enregistrez vos modifications avec ctrl + o, puis quittez avec ctrl + x.

  1. Démarrez vos services.
docker compose up -d

Résultat attendu :

[+] Running 4/4
 ✔ Network kafka-traefik-setup_default        Created                  0.2s
 ✔ Container kafka-traefik-setup-zookeeper-1  Started                  1.9s
 ✔ Container kafka-traefik-setup-traefik-1    Started                  1.9s
 ✔ Container kafka-traefik-setup-kafka-1      Started                  1.9s

Comment construire le système piloté par les événements

Comment créer des producteurs d’événements

Pour produire des événements dans Kafka, vous devrez mettre en place un producteur Kafka. Voici un exemple en Java.

  1. Créez un fichier kafka-producer.java.
nano kafka-producer.java
  1. Ajoutez la configuration suivante pour un producteur Kafka.
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;

import java.util.Properties;

public class SimpleProducer {
    public static void main(String[] args) {
        // Mettre en place les propriétés du producteur
        Properties props = new Properties();
        props.put("bootstrap.servers", "localhost:9092");
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

        // Créer le producteur
        KafkaProducer<String, String> producer = new KafkaProducer<>(props);

        try {
            // Envoyer un message au sujet "mon-sujet"
            ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", "key1", "Hello, Kafka!");
            RecordMetadata metadata = producer.send(record).get(); // Envoi synchrone
            System.out.printf("Sent message with key %s to partition %d with offset %d%n", 
                              record.key(), metadata.partition(), metadata.offset());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // Fermer le producteur
            producer.close();
        }
    }
}

Enregistrez vos modifications avec ctrl + o, puis quittez avec ctrl + x.

Dans la configuration ci-dessus, le producteur envoie un message avec la clé « key1 » et la valeur « Bonjour, Kafka ! » au sujet « mon-sujet ».

Comment configurer les sujets Kafka

Avant de produire ou de consommer des messages, vous devez créer des sujets dans Kafka.

  1. Utilisez le script kafka-topics.sh inclus dans votre installation Kafka pour créer un sujet.
kafka-topics.sh --bootstrap-server localhost:9092 --create --topic <TopicName> --partitions <NumberOfPartitions> --replication-factor <ReplicationFactor>

Par exemple, si vous souhaitez créer un sujet nommé my-topic avec 3 partitions et un facteur de réplication de 1, exécutez :

docker exec <Kafka Container ID> /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic my-topic --partitions 3 --replication-factor 1

Résultat attendu :

Created topic my-topic.
  1. Vérifiez pour confirmer si le sujet a été créé avec succès.
docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list

Résultat attendu :

my-topic

Comment Créer des Consommateurs d’Événements

Après avoir créé vos producteurs et sujets, vous pouvez créer des consommateurs pour lire les messages de ces sujets.

  1. Créez un fichier kafka-consumer.java.
nano kafka-consumer.java
  1. Ajoutez la configuration suivante pour un consommateur Kafka.
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.consumer.ConsumerRecord;

import java.time.Duration;
import java.util.Collections;
import java.util.Properties;

public class SimpleConsumer {
    public static void main(String[] args) {
        // Configurez les propriétés du consommateur
        Properties props = new Properties();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
        props.put(ConsumerConfig.GROUP_ID_CONFIG, "my-group");
        props.put(ConsumerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
        props.put(ConsumerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");

        // Créez le consommateur
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

        // Abonnez-vous au sujet
        consumer.subscribe(Collections.singletonList("my-topic"));

        try {
            while (true) {
                // Recherchez de nouveaux enregistrements
                ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
                for (ConsumerRecord<String, String> record : records) {
                    System.out.printf("Consumed message with key %s and value %s from partition %d at offset %d%n",
                                      record.key(), record.value(), record.partition(), record.offset());
                }
            }
        } finally {
            // Fermez le consommateur
            consumer.close();
        }
    }
}

Enregistrez vos modifications avec ctrl + o, puis quittez avec ctrl + x.

Dans la configuration ci-dessus, le consommateur s’abonne à my-topic et recherche continuellement de nouveaux messages. Lorsque des messages sont reçus, il affiche leurs clés et valeurs ainsi que des informations sur la partition et l’offset.

Comment Intégrer Traefik avec Kafka

Configurer Traefik en tant que serveur proxy inverse.

Intégrer Traefik en tant que serveur proxy inverse pour Kafka vous permet de gérer efficacement le trafic entrant tout en offrant des fonctionnalités telles que le routage dynamique et la terminaison SSL.

  1. Mettez à jour le fichier docker-compose.yml.
version: '3.8'

services:
  kafka:
    image: wurstmeister/kafka:latest
    ports:
      - "9092:9092"
    environment:
      KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9092,OUTSIDE://localhost:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
      KAFKA_LISTENERS: INSIDE://0.0.0.0:9092,OUTSIDE://0.0.0.0:9092
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.kafka.rule=Host(`kafka.example.com`)"
      - "traefik.http.services.kafka.loadbalancer.server.port=9092"

  zookeeper:
    image: wurstmeister/zookeeper:latest
    ports:
      - "2181:2181"

  traefik:
    image: traefik:v2.9
    ports:
      - "80:80"        # Trafic HTTP
      - "8080:8080"    # Tableau de bord Traefik (non sécurisé)
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

Dans cette configuration, remplacez kafka.example.com par votre nom de domaine réel. Les balises définissent les règles de routage que Traefik utilisera pour diriger le trafic vers le service Kafka.

  1. Redémarrez vos services.
docker compose up -d
  1. Accédez à votre tableau de bord Traefik en vous rendant sur http://localhost:8080 dans votre navigateur web.

    Équilibrage de charge avec Traefik

    Traefik fournit des capacités d’équilibrage de charge intégrées qui peuvent aider à distribuer les requêtes entre plusieurs instances de vos producteurs et consommateurs Kafka.

    Stratégies d’équilibrage de charge pour les microservices basés sur les événements

    1. Round Robin:

Par défaut, Traefik utilise une stratégie de round-robin pour distribuer de manière égale les requêtes entrantes sur toutes les instances disponibles d’un service. Cela est efficace pour équilibrer la charge lorsque plusieurs instances de producteurs ou consommateurs Kafka sont en cours d’exécution.

  1. Sessions persistantes:

Si vous avez besoin que les requêtes d’un client spécifique aillent toujours vers la même instance (par exemple, pour maintenir l’état de la session), vous pouvez configurer des sessions persistantes dans Traefik en utilisant des cookies ou des en-têtes.

  1. Vérifications de santé:

Configurez des vérifications de santé dans Traefik pour vous assurer que le trafic est uniquement dirigé vers des instances saines de vos services Kafka. Vous pouvez le faire en ajoutant des paramètres de vérification de santé dans les définitions de service de votre fichier docker-compose.yml:

    labels:
      - "traefik.http.services.kafka.loadbalancer.healthcheck.path=/health"
      - "traefik.http.services.kafka.loadbalancer.healthcheck.interval=10s"
      - "traefik.http.services.kafka.loadbalancer.healthcheck.timeout=3s"

Test de la configuration

Vérification de la production et de la consommation d’événements

  1. Kafka fournit des outils en ligne de commande intégrés pour les tests. Démarrez un producteur Console.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic my-topic

Après avoir exécuté cette commande, vous pouvez saisir des messages dans le terminal, qui seront envoyés au sujet Kafka spécifié.

  1. Démarrez une autre session de terminal et lancez un consommateur en console.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic my-topic --from-beginning

Cette commande affichera tous les messages dans my-topic, y compris ceux produits avant le démarrage du consommateur.

  1. Pour voir à quel point vos consommateurs suivent bien les producteurs, vous pouvez exécuter la commande suivante pour vérifier le retard d’un groupe de consommateurs spécifique.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group <your-consumer-group>

Surveillance et journalisation

  1. Métriques Kafka:

Kafka expose de nombreuses métriques qui peuvent être surveillées à l’aide de JMX (Java Management Extensions). Vous pouvez configurer JMX pour exporter ces métriques vers des systèmes de surveillance comme Prometheus ou Grafana. Les métriques clés à surveiller incluent :

  • Débit de messages: Le taux de messages produits et consommés.

  • Retard du consommateur: La différence entre le dernier décalage de message produit et le dernier décalage de message consommé.

  • Santé du courtier: Métriques liées à la performance du courtier, telles que les taux de demande et les taux d’erreur.

  1. Intégration de Prometheus et Grafana:

Pour visualiser les métriques Kafka, vous pouvez configurer Prometheus pour extraire les métriques de vos courtiers Kafka. Suivez ces étapes :

  • Activez JMX Exporter sur vos courtiers Kafka en l’ajoutant en tant qu’agent Java dans la configuration de votre courtier.

  • Configurez Prometheus en ajoutant un travail de raclage dans son fichier de configuration (prometheus.yml) qui pointe vers votre point de terminaison JMX Exporter.

  • Utilisez Grafana pour créer des tableaux de bord qui visualisent ces métriques en temps réel.

Comment mettre en œuvre la surveillance pour Traefik

  1. Point de terminaison des métriques Traefik.

Traefik prend en charge la sortie intégrée des métriques via Prometheus. Pour activer cette fonctionnalité, ajoutez la configuration suivante dans la définition de service Traefik dans votre fichier docker-compose.yml:

    command:
      - "--metrics.prometheus=true"
      - "--metrics.prometheus.addservice=true"
  1. Visualiser les métriques Traefik avec Grafana.

Une fois que Prometheus récupère les métriques de Traefik, vous pouvez les visualiser en utilisant Grafana:

  • Créez un nouveau tableau de bord dans Grafana et ajoutez des panneaux qui affichent les principales métriques de Traefik telles que:

  • traefik_entrypoint_requests_total: Nombre total de requêtes reçues.

  • traefik_backend_request_duration_seconds: Temps de réponse des services backend.

  • traefik_service_requests_total: Total des requêtes transmises aux services backend.

  1. Configuration des alertes.

Configurez des alertes dans Prometheus ou Grafana en fonction de seuils spécifiques (par exemple, un décalage élevé des consommateurs ou des taux d’erreur accrus).

Conclusion

Dans ce guide, vous avez mis en œuvre avec succès une architecture orientée événements (EDA) en utilisant Kafka et Traefik dans l’environnement Ubuntu 24.04.

Ressources supplémentaires

Pour en savoir plus, vous pouvez visiter :