In moderne systeemontwerp richt Event-Driven Architecture (EDA) zich op het creëren, detecteren, gebruiken en reageren op gebeurtenissen binnen een systeem. Gebeurtenissen zijn belangrijke gebeurtenissen die hardware of software van een systeem kunnen beïnvloeden, zoals gebruikersacties, statuswijzigingen of gegevensupdates.

EDA maakt het mogelijk dat verschillende delen van een toepassing op een losgekoppelde manier met elkaar kunnen communiceren, waardoor ze kunnen communiceren via gebeurtenissen in plaats van directe oproepen. Deze opstelling stelt componenten in staat om onafhankelijk te werken, te reageren op gebeurtenissen asynchroon en zich aan te passen aan veranderende bedrijfsbehoeften zonder grote systeemherconfiguratie, wat de wendbaarheid bevordert.

Nieuwe en moderne toepassingen vertrouwen nu zwaar op realtime gegevensverwerking en responsiviteit. De belangrijkheid van EDA kan niet worden overschat omdat het het kader biedt dat die vereisten ondersteunt. Door gebruik te maken van asynchrone communicatie en op gebeurtenissen gebaseerde interacties, kunnen systemen efficiënt omgaan met grote hoeveelheden transacties en prestaties behouden onder instabiele belastingen. Deze functies worden vooral gewaardeerd in omgevingen waar veranderingen zeer spontaan zijn, zoals e-commerceplatforms of IoT-toepassingen.

Enkele belangrijke componenten van EDA zijn:

  • Gebeurtenisbronnen: Dit zijn de producenten die gebeurtenissen genereren wanneer belangrijke acties binnen het systeem plaatsvinden. Voorbeelden zijn gebruikersinteracties of gegevenswijzigingen.

  • Luisteraars: Dit zijn entiteiten die zich abonneren op specifieke gebeurtenissen en reageren wanneer die gebeurtenissen zich voordoen. Luisteraars stellen het systeem in staat om dynamisch te reageren op veranderingen.

  • Handlers: Deze zijn verantwoordelijk voor het verwerken van de gebeurtenissen zodra ze worden gedetecteerd door luisteraars, het uitvoeren van de noodzakelijke bedrijfslogica of workflows die worden geactiveerd door de gebeurtenis.

In dit artikel leer je hoe je op gebeurtenissen gebaseerde gegevensverwerking implementeert met Traefik, Kafka en Docker.

Hier is een eenvoudige toepassing gehost op GitHub die je snel kunt uitvoeren om een overzicht te krijgen van wat je vandaag zult bouwen.

Inhoudsopgave

Dit is wat we zullen behandelen:

Laten we beginnen!

Vereisten

Voordat je begint:

  • Implementeer een Ubuntu 24.04 instantie met minimaal 4 GB RAM en een minimum van 20 GB vrije schijfruimte om Docker-images, containers en Kafka-gegevens te accommoderen.

  • Open de instantie met een niet-rootgebruiker met sudo-rechten.

  • Werk de pakketindex bij.

sudo apt update

Begrip van de Technologieën

Apache Kafka

Apache Kafka is een gedistribueerd gebeurtenissenstroomplatform gebouwd voor data pipelines met een hoog doorvoervermogen en real-time streamingtoepassingen. Het fungeert als ruggengraat voor het implementeren van EDA door efficiënt grote hoeveelheden gebeurtenissen te beheren. Kafka maakt gebruik van een publiceer-abonneemodel waarbij producenten gebeurtenissen naar onderwerpen sturen en consumenten zich abonneren op deze onderwerpen om de gebeurtenissen te ontvangen.

Enkele van de belangrijkste kenmerken van Kafka zijn:

  • Hoge doorvoer: Kafka is in staat om miljoenen gebeurtenissen per seconde te verwerken met lage latentie, waardoor het geschikt is voor toepassingen met een hoog volume.

  • Fouttolerantie: Kafka’s gedistribueerde architectuur zorgt voor gegevensduurzaamheid en beschikbaarheid, zelfs bij serverstoringen. Het repliceert gegevens over meerdere brokers binnen een cluster.

  • Schaalbaarheid: Kafka kan eenvoudig horizontaal worden geschaald door meer brokers aan het cluster toe te voegen of partities aan topics, waardoor groeiende gegevensbehoeften worden ondersteund zonder significante herconfiguratie.

Traefik

Traefik is een moderne HTTP-reverse-proxy en load balancer die speciaal is ontworpen voor microservices-architecturen. Het ontdekt automatisch services die in uw infrastructuur draaien en routeert het verkeer dienovereenkomstig. Traefik vereenvoudigt het beheer van microservices door dynamische routeringsmogelijkheden te bieden op basis van servicemetadata.

Enkele van de belangrijkste functies van Traefik zijn:

  • Dynamische configuratie: Traefik werkt automatisch zijn routeringsconfiguratie bij wanneer services worden toegevoegd of verwijderd, waardoor handmatige interventie wordt geëlimineerd.

  • Load Balancer: Het verdeelt efficiënt binnenkomende verzoeken over meerdere service-instanties, waardoor de prestaties en betrouwbaarheid verbeteren.

  • Geïntegreerd Dashboard: Traefik biedt een gebruiksvriendelijk dashboard voor het monitoren van verkeer en de gezondheid van services in realtime.

Door Kafka en Traefik te gebruiken in een op gebeurtenissen gebaseerde architectuur, kunt u responsieve systemen bouwen die efficiënt omgaan met real-time gegevensverwerking, terwijl hoge beschikbaarheid en schaalbaarheid worden gehandhaafd.

Hoe u de omgeving instelt

Hoe u Docker installeert op Ubuntu 24.04

  1. Installeer de vereiste pakketten.
sudo apt install ca-certificates curl gnupg lsb-release
  1. Voeg de officiële GPG-sleutel van Docker toe.
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  1. Voeg het Docker-repository toe aan uw APT-bronnen.
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. Werk de pakketindex opnieuw bij en installeer Docker Engine met de Docker Compose-plugin.
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  1. Controleer om de installatie te verifiëren.
sudo docker run hello-world

Verwachte uitvoer:

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.

Hoe u Docker Compose configureert

Docker Compose vereenvoudigt het beheer van multi-container toepassingen, waardoor u services kunt definiëren en uitvoeren in een enkel bestand.

  1. Maak een projectdirectory
mkdir ~/kafka-traefik-setup && cd ~/kafka-traefik-setup
  1. Maak een docker-compose.yml-bestand.
nano docker-compose.yml
  1. Voeg de volgende configuratie toe aan het bestand om uw services te definiëren.
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"       # HTTP verkeer
      - "8080:8080"   # Traefik dashboard (onveilig)
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

Sla je wijzigingen op met ctrl + o, en verlaat met ctrl + x.

  1. Start je diensten.
docker compose up -d

Verwachte uitvoer:

[+] 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

Hoe een op gebeurtenissen aangedreven systeem te bouwen

Hoe gebeurtenisproducenten te creëren

Om gebeurtenissen in Kafka te produceren, moet je een Kafka-producent implementeren. Hieronder staat een voorbeeld met Java.

  1. Maak een bestand kafka-producer.java.
nano kafka-producer.java
  1. Voeg de volgende configuratie toe voor een Kafka-producent.
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) {
        // Stel de producenteigenschappen in
        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");

        // Maak de producent aan
        KafkaProducer<String, String> producer = new KafkaProducer<>(props);

        try {
            // Stuur een bericht naar het onderwerp "my-topic"
            ProducerRecord<String, String> record = new ProducerRecord<>("my-topic", "key1", "Hello, Kafka!");
            RecordMetadata metadata = producer.send(record).get(); // Synchroniseren verzenden
            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 {
            // Sluit de producent
            producer.close();
        }
    }
}

Sla je wijzigingen op met ctrl + o, en verlaat met ctrl + x.

In de bovenstaande configuratie verstuurt de producent een bericht met de sleutel “key1” en de waarde “Hallo, Kafka!” naar het onderwerp “my-topic”.

Hoe Kafka-onderwerpen in te stellen

Voordat je berichten kunt produceren of consumeren, moet je onderwerpen in Kafka aanmaken.

  1. Gebruik het kafka-topics.sh script dat is inbegrepen bij je Kafka-installatie om een topic aan te maken.
kafka-topics.sh --bootstrap-server localhost:9092 --create --topic <TopicName> --partitions <NumberOfPartitions> --replication-factor <ReplicationFactor>

Bijvoorbeeld, als je een topic met de naam my-topic met 3 partities en een replicafactor van 1 wilt aanmaken, voer dan het volgende uit:

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

Verwachte uitvoer:

Created topic my-topic.
  1. Controleer om te bevestigen of het topic succesvol is aangemaakt.
docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list

Verwachte uitvoer:

my-topic

Hoe Event Consumers Aan te maken

Nadat je je producers en topics hebt aangemaakt, kun je consumenten creëren om berichten van die topics te lezen.

  1. Maak een bestand kafka-consumer.java aan.
nano kafka-consumer.java
  1. Voeg de volgende configuratie toe voor een Kafka consument.
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) {
        // Stel de consumenteigenschappen in
        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");

        // Maak de consument aan
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

        // Abonneer op het topic
        consumer.subscribe(Collections.singletonList("my-topic"));

        try {
            while (true) {
                // Poll voor nieuwe records
                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 {
            // Sluit de consument af
            consumer.close();
        }
    }
}

Sla je wijzigingen op met ctrl + o, en verlaat met ctrl + x.

In de bovenstaande configuratie abonneert de consument zich op my-topic en pollt continu voor nieuwe berichten. Wanneer berichten worden ontvangen, worden hun sleutels en waarden samen met partitie- en offsetinformatie afgedrukt.

Hoe Traefik te integreren met Kafka

Configureer Traefik als een Reverse Proxy.

Integratie van Traefik als een reverse proxy voor Kafka stelt je in staat om binnenkomend verkeer efficiënt te beheren, terwijl het functies biedt zoals dynamische routering en SSL-terminatie.

  1. Werk het docker-compose.yml bestand bij.
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"        # HTTP verkeer
      - "8080:8080"    # Traefik dashboard (onveilig)
    command:
      - "--api.insecure=true"
      - "--providers.docker=true"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"

Vervang in deze configuratie kafka.example.com door je werkelijke domeinnaam. De labels definiëren de routeringsregels die Traefik zal gebruiken om verkeer naar de Kafka-service te leiden.

  1. Herstart je services.
docker compose up -d
  1. Toegang tot je Traefik dashboard door http://localhost:8080 in je webbrowser te openen.

    Load Balancing met Traefik

    Traefik biedt ingebouwde load balancing mogelijkheden die kunnen helpen om verzoeken over meerdere instanties van je Kafka-producers en -consumenten te verspreiden.

    Strategieën voor Load Balancing in Event-Driven Microservices

    1. Round Robin:

Standaard gebruikt Traefik een round-robin-strategie om inkomende verzoeken gelijkmatig over alle beschikbare instanties van een service te verdelen. Dit is effectief voor het balanceren van de belasting wanneer er meerdere instanties van Kafka-producenten of -consumenten actief zijn.

  1. Sticky Sessions:

Als u wilt dat verzoeken van een specifieke client altijd naar dezelfde instantie gaan (bijvoorbeeld om sessiestatus te behouden), kunt u plakkerige sessies configureren in Traefik met behulp van cookies of headers.

  1. Health Checks:

Configureer gezondheidscontroles in Traefik om ervoor te zorgen dat verkeer alleen wordt doorgestuurd naar gezonde instanties van uw Kafka-services. U kunt dit doen door gezondheidscontroleparameters toe te voegen in de service-definities in uw docker-compose.yml-bestand:

    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"

Testen van de Setup

Verifiëren van Event Productie en Consumptie

  1. Kafka biedt ingebouwde opdrachtregeltools voor testen. Start een Console-producent.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-console-producer.sh --broker-list localhost:9092 --topic my-topic

Nadat u deze opdracht heeft uitgevoerd, kunt u berichten typen in de terminal die worden verzonden naar het opgegeven Kafka-onderwerp.

  1. Start een andere terminalsessie en start een console-consument.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic my-topic --from-beginning

Dit commando toont alle berichten in my-topic, inclusief die geproduceerd voordat de consument begon.

  1. Om te zien hoe goed uw consumenten bijblijven met producenten, kunt u het volgende commando uitvoeren om de vertraging voor een specifieke consumentengroep te controleren.
    docker exec -it kafka-traefik-setup-kafka-1 /opt/kafka/bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group <your-consumer-group>

Monitoring en Logging

  1. Kafka Statistieken:

Kafka biedt talloze statistieken die kunnen worden gemonitord met JMX (Java Management Extensions). U kunt JMX configureren om deze statistieken te exporteren naar monitorsystemen zoals Prometheus of Grafana. Belangrijke statistieken om te monitoren zijn:

  • Berichten Doorvoer: De snelheid van geproduceerde en geconsumeerde berichten.

  • Consumenten Vertraging: Het verschil tussen de offset van het laatst geproduceerde bericht en de offset van het laatst geconsumeerde bericht.

  • Broker Gezondheid: Statistieken gerelateerd aan de prestaties van de broker, zoals aanvraagpercentages en foutpercentages.

  1. Integratie van Prometheus en Grafana:

Om Kafka-statistieken te visualiseren, kunt u Prometheus instellen om statistieken van uw Kafka-brokers te verzamelen. Volg deze stappen:

  • Schakel JMX Exporter in op uw Kafka-brokers door het toe te voegen als een Java-agent in uw brokerconfiguratie.

  • Configureer Prometheus door een scrape taak toe te voegen in het configuratiebestand (prometheus.yml) dat wijst naar uw JMX Exporter-eindpunt.

  • Gebruik Grafana om dashboards te maken die deze metingen in realtime visualiseren.

Hoe Monitoring implementeren voor Traefik

  1. Traefik Metrics-eindpunt.

Traefik biedt ingebouwde ondersteuning voor het exporteren van metingen via Prometheus. Voeg om deze functie in te schakelen de volgende configuratie toe in de definitie van uw Traefik-service binnen docker-compose.yml:

    command:
      - "--metrics.prometheus=true"
      - "--metrics.prometheus.addservice=true"
  1. Visualiseer Traefik-metingen met Grafana.

Zodra Prometheus Traefik-metingen schraapt, kunt u ze visualiseren met Grafana:

  • Maak een nieuw dashboard in Grafana en voeg panelen toe die belangrijke Traefik-metingen weergeven, zoals:

  • traefik_entrypoint_requests_total: Totaal aantal ontvangen verzoeken.

  • traefik_backend_request_duration_seconds: Responstijden van backend-services.

  • traefik_service_requests_total: Totaal aantal verzoeken doorgestuurd naar backend-services.

  1. Instellen van waarschuwingen.

Configureer waarschuwingen in Prometheus of Grafana op basis van specifieke drempels (bijv. hoge consumentenvertraging of verhoogde foutpercentages).

Conclusie

In deze handleiding heeft u met succes Event Driven Architecture (EDA) geïmplementeerd met behulp van Kafka en Traefik binnen de Ubuntu 24.04-omgeving.

Extra bronnen

Voor meer informatie kunt u terecht op: