DataPartner365

Jouw partner voor datagedreven groei en inzichten

Streaming Data met Apache Kafka: Praktische Gids

Gepubliceerd: 21 maart 2026
Leestijd: 12 minuten
Data Engineering

Leer hoe Apache Kafka real-time datastromen verwerkt. Van basisconcepten tot productie-implementatie voor Nederlandse data engineers.

Wat is Apache Kafka en waarom is het in 2026 onmisbaar?

In een wereld waar data in milliseconden gegenereerd wordt door IoT-sensoren, klantinteracties, betalingssystemen en microservices, is het verwerken van die data in real-time geen luxe meer — het is een bedrijfskritische noodzaak. Apache Kafka is uitgegroeid tot het standaard platform voor event streaming en staat bij vrijwel elke grote organisatie in het hart van de datainfrastructuur.

Kafka werd oorspronkelijk ontwikkeld door LinkedIn in 2011 en later open-source uitgebracht via de Apache Software Foundation. Inmiddels wordt het platform gebruikt door meer dan 80% van de Fortune 100-bedrijven. In Nederland zien we Kafka opduiken bij banken, webshops, logistieke bedrijven en zorgorganisaties — overal waar data continu stroomt en directe actie vereist.

Definitie: Apache Kafka

Apache Kafka is een gedistribueerd event streaming platform dat in staat is miljoenen berichten per seconde te publiceren, op te slaan, te verwerken en te distribueren. Kafka fungeert als een gecentraliseerde, duurzame message bus tussen producenten (producers) en consumenten (consumers) van data.

Waarom is Kafka in 2026 zo relevant? De opkomst van AI-toepassingen die real-time data vereisen, de explosieve groei van IoT-apparaten, en de verschuiving naar event-driven architecturen maken Kafka meer relevant dan ooit. Denk aan fraudedetectie bij betalingen die binnen 50 milliseconden moet reageren, of een aanbevelingssysteem dat direct aanpast op basis van het laatste klikgedrag.

Hoge doorvoer

Verwerkt miljoenen berichten per seconde met lage latency, zelfs op commodity hardware.

Duurzame opslag

Berichten worden op schijf bewaard met configureerbare retentie — van uren tot jaren.

Horizontaal schaalbaar

Voeg eenvoudig brokers toe aan het cluster om capaciteit te vergroten zonder downtime.

Hoe werkt Apache Kafka? De kernconcepten uitgelegd

Om Kafka effectief te gebruiken, moet je de fundamentele bouwstenen begrijpen. De architectuur is elegant maar krachtig — een combinatie van gedistribueerde log-opslag en een publish-subscribe messaging model.

1

Topics & Partities

Een topic is een categorie of feed-naam waaronder berichten worden gepubliceerd — vergelijk het met een database-tabel. Elk topic wordt opgesplitst in meerdere partities, die elk een geordende, onveranderlijke reeks berichten vormen. Partitionering maakt parallelle verwerking mogelijk en is de sleutel tot Kafka's schaalbaarheid.

2

Producers

Een producer is elke applicatie die berichten naar een Kafka-topic publiceert. Producers bepalen in welke partitie een bericht terechtkomt — op basis van een sleutel, round-robin of een aangepaste partitioner. Dit biedt volledige controle over de berichtdistributie.

3

Brokers & Clusters

Een broker is een Kafka-serverinstantie die topics en partities beheert. Meerdere brokers vormen samen een cluster. Elk cluster heeft een controller-broker die verantwoordelijk is voor het beheer van partitietoewijzingen en failover. Moderne Kafka-versies (3.x+) gebruiken KRaft (Kafka Raft) in plaats van ZooKeeper voor clusterbeheer.

4

Consumers & Consumer Groups

Een consumer leest berichten van een of meerdere topics. Consumers die samenwerken in een consumer group verdelen de partities onder elkaar, wat parallelle verwerking mogelijk maakt. Elke partitie wordt door precies één consumer binnen een groep gelezen.

5

Offsets

Elke bericht in een partitie heeft een uniek volgnummer: de offset. Consumers bewaren bij welke offset ze zijn gebleven, waardoor ze na een herstart precies kunnen doorgaan waar ze gebleven zijn. Dit mechanisme garandeert betrouwbare berichtverwerking.

De data flow in één overzicht

Component Rol Analogie
Producer Schrijft berichten naar topics Krantenuitgever
Topic Logische categorie van berichten Krantentitel / rubriek
Partitie Fysieke opdeeling van een topic Stapel kranten per wijk
Broker Bewaart en distribueert berichten Distributiecentrum
Consumer Group Groep die samen berichten verwerkt Bezorgers per regio
Offset Positiemarker per consumer/partitie Bladwijzer in de krant

Praktische Codevoorbeelden: Kafka in Python

Genoeg theorie — laten we Kafka in de praktijk bekijken. We gebruiken de confluent-kafka Python library, de meest betrouwbare en feature-rijke optie voor productieomgevingen.

Installatie

pip install confluent-kafka

1. Een eenvoudige Producer

Dit voorbeeld simuleert een bestellingssysteem dat order-events publiceert naar het topic orders. We gebruiken JSON-serialisatie en een message key op basis van klant-ID voor consistente partitionering.

import json
import time
from datetime import datetime
from confluent_kafka import Producer

# Configuratie voor lokale of Cloud Kafka broker
producer_config = {
    'bootstrap.servers': 'localhost:9092',
    'client.id': 'order-producer',
    # Productie aanbevelingen:
    'acks': 'all',              # Wacht op bevestiging van alle replica's
    'retries': 3,               # Maximaal 3 pogingen bij fout
    'linger.ms': 5,             # Wacht 5ms om berichten te batchen
    'batch.size': 16384,        # 16KB batch size
    'compression.type': 'lz4'  # Comprimeer berichten voor minder bandbreedte
}

producer = Producer(producer_config)

def delivery_report(err, msg):
    """Callback die wordt aangeroepen na succesvolle of mislukte levering."""
    if err is not None:
        print(f"❌ Levering mislukt voor bericht: {err}")
    else:
        print(f"✅ Bericht geleverd aan topic '{msg.topic()}' "
              f"[partitie {msg.partition()}] @ offset {msg.offset()}")

def publish_order_event(order_id: int, customer_id: str, items: list, total: float):
    """Publiceert een order-event naar het 'orders' topic."""
    event = {
        'order_id': order_id,
        'customer_id': customer_id,
        'items': items,
        'total': total,
        'timestamp': datetime.utcnow().isoformat(),
        'status': 'CREATED'
    }
    
    producer.produce(
        topic='orders',
        key=customer_id,         # Zelfde klant → zelfde partitie (volgorde gegarandeerd)
        value=json.dumps(event).encode('utf-8'),
        callback=delivery_report
    )
    producer.poll(0)  # Trigger delivery callbacks

# Simuleer 10 orders
for i in range(1, 11):
    publish_order_event(
        order_id=i,
        customer_id=f"klant_{i % 3}",  # 3 klanten, roterende toewijzing
        items=[{"sku": "PROD-001", "qty": i}],
        total=round(i * 24.99, 2)
    )
    time.sleep(0.1)

# Zorg dat alle berichten verstuurd zijn
producer.flush()
print("Alle order-events gepubliceerd.")

2. Een Consumer met Consumer Group

Onderstaande consumer leest de order-events en verwerkt ze. Door de group.id te configureren, kunnen meerdere instanties van deze consumer tegelijk draaien en de verwerking verdelen.

import json
from confluent_kafka import Consumer, KafkaError, KafkaException

consumer_config = {
    'bootstrap.servers': 'localhost:9092',
    'group.id': 'order-processing-service',
    'auto.offset.reset': 'earliest',   # Start bij het begin als er geen offset is
    'enable.auto.commit': False,        # Handmatig committen voor betere controle
    'max.poll.interval.ms': 300000      # 5 minuten max verwerkingstijd per poll
}

consumer = Consumer(consumer_config)
consumer.subscribe(['orders'])

def process_order(event: dict) -> bool:
    """Verwerk een binnenkomend order-event. Retourneert True bij succes."""
    try:
        print(f"📦 Verwerk order #{event['order_id']} "
              f"voor klant {event['customer_id']} "
              f"(€{event['total']})")
        # Hier zou je de order valideren, opslaan in database, etc.
        return True
    except Exception as e:
        print(f"Fout bij verwerken order: {e}")
        return False

print("Order consumer gestart. Wachten op berichten...")
try:
    while True:
        msg = consumer.poll(timeout=1.0)
        
        if msg is None:
            continue  # Geen bericht in dit poll-interval
            
        if msg.error():
            if msg.error().code() == KafkaError._PARTITION_EOF:
                print(f"Einde van partitie {msg.partition()} bereikt")
            else:
                raise KafkaException(msg.error())
        else:
            event = json.loads(msg.value().decode('utf-8'))
            
            if process_order(event):
                # Commit ALLEEN na succesvolle verwerking (at-least-once semantics)
                consumer.commit(asynchronous=False)
            else:
                print(f"⚠️ Bericht niet verwerkt, offset niet gecommit")

except KeyboardInterrupt:
    print("\nConsumer gestopt.")
finally:
    consumer.close()  # Altijd netjes afsluiten voor juiste rebalancing

3. Stream Processing met Kafka Streams (via Faust)

Voor complexere stream processing gebruiken we Faust, een Python stream processing library geïnspireerd door Kafka Streams.

import faust
from datetime import timedelta

app = faust.App(
    'fraud-detection',
    broker='kafka://localhost:9092',
    value_serializer='json'
)

class OrderEvent(faust.Record):
    order_id: int
    customer_id: str
    total: float
    timestamp: str

orders_topic = app.topic('orders', value_type=OrderEvent)
fraud_alerts_topic = app.topic('fraud-alerts')

# Window: tel orders per klant in de laatste 5 minuten
order_count_table = app.Table(
    'order-counts',
    default=int,
).tumbling(timedelta(minutes=5), expires=timedelta(hours=1))

@app.agent(orders_topic)
async def detect_fraud(orders):
    async for order in orders.group_by(OrderEvent.customer_id):
        # Tel het aantal orders per klant per tijdvenster
        order_count_table[order.customer_id] += 1
        count = order_count_table[order.customer_id].current()
        
        # Fraudedetectie: meer dan 10 orders in 5 minuten = verdacht
        if count > 10:
            alert = {
                'customer_id': order.customer_id,
                'order_count': count,
                'latest_order_id': order.order_id,
                'alert_type': 'HIGH_ORDER_FREQUENCY'
            }
            await fraud_alerts_topic.send(value=alert)
            print(f"🚨 Fraudealarm voor {order.customer_id}: {count} orders in 5 min!")

if __name__ == '__main__':
    app.main()

Pro-tip: Schema Registry

Gebruik in productie altijd Confluent Schema Registry met Avro of Protobuf serialisatie. Dit garandeert dat producers en consumers het eens zijn over de datastructuur en voorkomt brekende wijzigingen. Installeer met: pip install confluent-kafka[avro]

Kafka vs. Alternatieven: Wanneer Kies je Wat?

Kafka is krachtig, maar niet altijd de beste keuze. Hier is een eerlijke vergelijking met de belangrijkste alternatieven:

Platform Doorvoer Latency Complexiteit Retentie Best voor
Apache Kafka ⭐⭐⭐⭐⭐ Extreem hoog Laag (ms) Hoog Configureerbaar (dagen–jaren) Event streaming, hoge volumes, audit logs
RabbitMQ ⭐⭐⭐ Gemiddeld Zeer laag (µs) Laag Tot verwerking Task queues, RPC, eenvoudige messaging
AWS Kinesis ⭐⭐⭐⭐ Hoog Laag (ms) Laag (managed) 7 dagen standaard AWS-native, serverless streaming
Azure Event Hubs ⭐⭐⭐⭐ Hoog Laag (ms) Laag (managed) 1–90 dagen Azure-native, Kafka-compatibel API
Google Pub/Sub ⭐⭐⭐⭐ Hoog Laag (ms) Laag (managed) 7 dagen standaard GCP-native, global delivery
Apache Pulsar ⭐⭐⭐⭐⭐ Extreem hoog Laag (ms) Hoog Configureerbaar Multi-tenancy, geo-replicatie

Keuzeadvies voor Nederlandse organisaties

  • Je bent al in AWS/Azure/GCP? → Overweeg de managed variant (Kinesis, Event Hubs, Pub/Sub) voor minder operationele overhead.
  • Heb je meer dan 100.000 berichten/sec nodig? → Kafka of Pulsar zijn dan de juiste keuze.
  • Eenvoudige taakwachtrijen of microservice-communicatie? → RabbitMQ is eenvoudiger en volstaat.
  • Compliance en audit logs vereist? → Kafka's duurzame retentie is uniek waardevol.

Praktijkcase: Real-time Fraude Detectie bij een Nederlandse Bank

Use Case: Betalingsverwerking

Context: Een Nederlandse bank verwerkt dagelijks 3 miljoen betaaltransacties. Het bestaande batch-systeem detecteerde fraude gemiddeld 4 uur na de transactie — te laat om schade te beperken.

Oplossing met Kafka:

  • Elk betaalevent wordt gepubliceerd naar het Kafka-topic payment-transactions met de rekening-ID als key
  • Een Kafka Streams applicatie verrijkt transacties met klantprofiel-data via een KTable join
  • Een ML-model (via Faust) scoort elke transactie in real-time op fraudekans
  • Verdachte transacties gaan naar het topic fraud-alerts dat direct de autorisatieservice triggert
  • Alle events worden via Kafka Connect naar een data warehouse geladen voor forensisch onderzoek

Resultaat:

  • Detectietijd gedaald van 4 uur naar 230 milliseconden
  • Fraudeverlies met 67% gereduceerd in het eerste kwartaal
  • Systeem verwerkt pieken tot 85.000 transacties per seconde zonder degradatie

Best Practices voor Productie

Kafka in productie draaien vereist aandacht voor meerdere aspecten. Hier zijn de kritieke aandachtspunten die we in de praktijk tegenkomen:

Partitie-strategie

Begin met 3× het aantal brokers als partitieaantal. Te weinig partities beperkt parallellisme; te veel verhoogt de overhead. Gebruik betekenisvolle keys voor gerelateerde volgorde.

Replicatie factor

Stel replication.factor=3 in voor productietopics. Dit garandeert dat data bewaard blijft bij uitval van één of twee brokers. Combineer met min.insync.replicas=2.

Monitoring

Monitor altijd consumer lag (verschil tussen laatste offset en consumer positie). Gebruik Prometheus + Grafana of Confluent Control Center. Stel alerts in bij lag > 10.000 berichten.

Kritieke configuratie-instellingen

# server.properties - Broker configuratie voor productie
# Retentie
log.retention.hours=168          # 7 dagen retentie
log.segment.bytes=1073741824     # 1GB per segment
log.retention.check.interval.ms=300000

# Performance
num.io.threads=8
num.network.threads=3
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600

# Replicatie betrouwbaarheid
default.replication.factor=3
min.insync.replicas=2
unclean.leader.election.enable=false  # KRITIEK: voorkomt dataverlies

# Compressie op broker-niveau
compression.type=producer       # Respecteer producer-keuze

# --- Producer configuratie voor exact-once semantics ---
# producer.properties
enable.idempotence=true
acks=all
max.in.flight.requests.per.connection=5
retries=2147483647

# --- Consumer configuratie ---
# consumer.properties
isolation.level=read_committed   # Lees alleen gecommitte transacties
fetch.min.bytes=1024
fetch.max.wait.ms=500

Veelgemaakte fouten om te vermijden

  1. Te weinig partities bij aanmaak — Partities later toevoegen verstoort de key-gebaseerde volgorde. Plan vooruit.
  2. Auto-commit ingeschakeld laten — Gebruik enable.auto.commit=false en commit handmatig na succesvolle verwerking.
  3. Geen dead letter queue — Stel altijd een fallback-mechanisme in voor berichten die herhaaldelijk mislukken.
  4. Grote berichten sturen — Kafka is geoptimaliseerd voor kleine berichten (<1MB). Sla grote payloads extern op en stuur alleen de referentie.
  5. ZooKeeper in 2026 — Migreer naar KRaft mode (Kafka zonder ZooKeeper). ZooKeeper-support wordt afgebouwd.

Kafka Connect: data pipelines zonder code

Kafka Connect is een krachtige tool voor het bouwen van data pipelines tussen Kafka en externe systemen, zonder dat je code hoeft te schrijven. Hier is een voorbeeld van een PostgreSQL source connector configuratie:

{
  "name": "postgres-source-connector",
  "config": {
    "connector.class": "io.debezium.connector.postgresql.PostgresConnector",
    "database.hostname": "postgres-host",
    "database.port": "5432",
    "database.user": "kafka_user",
    "database.password": "${file:/secrets/postgres.properties:password}",
    "database.dbname": "orders_db",
    "database.server.name": "orders-postgres",
    "table.include.list": "public.orders,public.customers",
    "plugin.name": "pgoutput",
    "publication.autocreate.mode": "filtered",
    "topic.prefix": "cdc",
    "transforms": "unwrap",
    "transforms.unwrap.type": "io.debezium.transforms.ExtractNewRecordState",
    "transforms.unwrap.drop.tombstones": "false",
    "key.converter": "io.confluent.kafka.serializers.KafkaAvroSerializer",
    "value.converter": "io.confluent.kafka.serializers.KafkaAvroSerializer",
    "key.converter.schema.registry.url": "http://schema-registry:8081",
    "value.converter.schema.registry.url": "http://schema-registry:8081"
  }
}

Dit Debezium connector leest alle wijzigingen (Change Data Capture) uit PostgreSQL en publiceert ze automatisch naar Kafka. Zo bouw je in minuten een CDC-pipeline zonder een regel applicatiecode.

Conclusie: Wanneer Wel en Wanneer Niet Kafka?

Apache Kafka is een uitzonderlijk krachtig platform, maar het introduceert ook significante operationele complexiteit. Een eerlijke afweging is essentieel.

Scenario Aanbeveling Reden
Hoog volume event streaming (>100K events/sec) ✅ Kafka Kafka is hiervoor gebouwd
Audit logs die jaren bewaard moeten worden ✅ Kafka Duurzame, configureerbare retentie
Eenvoudige taakwachtrij voor microservices ⚠️ Overweeg RabbitMQ Kafka is te complex voor dit use case
Team
Abdullah Özisik - AI Data Engineer

👨‍💻 Over de auteur

Abdullah Özisik — Data Engineer met specialisatie in AI-integratie en MLOps. Expert in het bouwen van intelligente data pipelines die gebruik maken van machine learning en generative AI voor geautomatiseerde data processing en optimalisatie.