Apache Kafka Fundamentals: onderwerpen, partities, compensaties en consumentengroepen
Kafka is niet zomaar een berichtenwachtrij: het is een gedistribueerd commitlogboek ontworpen om miljoenen gebeurtenissen per seconde te ondersteunen met gegarandeerde duurzaamheid. Ontdek in deze fundamentele gids de interne structuur van onderwerpen en partities en hoe tracking-offsets werken precieze locatie, en waarom de consumentengroep het belangrijkste mechanisme is voor het parallel opschalen van de consumptie.
Waarom Kafka anders is dan een traditionele Coda
Bij het ontwerpen van een gedistribueerd systeem dat stromen van gebeurtenissen in realtime moet verwerken, is de eerste verleiding het gebruik van een klassieke berichtenwachtrij. zoals RabbitMQ of ActiveMQ. Deze oplossingen werken goed voor eenvoudige scenario's, maar hebben een belangrijke structurele beperking: eenmaal de consument het bericht heeft geconsumeerd, wordt het bericht verwijderd. Er is geen mogelijkheid om het te herlezen, om meer onafhankelijke consumenten te hebben die het verwerken anders, of om de hele geschiedenis van gebeurtenissen opnieuw af te spelen.
Apache Kafka werd in 2011 geboren op LinkedIn met een radicaal andere filosofie: berichten (genaamd dossier) zijn geschreven in a log alleen toevoegen en blijf daar gedurende een configureerbare periode (standaard: 7 dagen). Verschillende consumenten kunnen soms dezelfde gegevens lezen verschillend, elk houdt zijn positie bij via degecompenseerd. Dit patroon maakt van Kafka veel meer dan een wachtrij: wordt de bron van waarheid voor de volledige gebeurtenisgeschiedenis van uw systeem.
Kafka in 2026: sleutelnummers
- Ruim gebruikt 80% van Fortune 500-bedrijven voor het streamen van gebruiksscenario's
- Kafka 4.0 (maart 2025) heeft ZooKeeper definitief verwijderd en is verhuisd naar KRaft
- Theoretische doorvoer: 1 miljoen+ berichten/seconde voor makelaars (grondstofhardware)
- Confluent Cloud: beheerde Kafka beschikbaar op AWS, GCP, Azure met latentie < 10 ms p99
- Ecosysteem: 200+ connectoren via Kafka Connect, Kafka Streams, Apache Flink-integratie
Het fundamentele model: makelaar, onderwerp en partitie
Broker: het clusterknooppunt
Un makelaar het is gewoon een Kafka-server. Een Kafka-cluster bestaat uit een of meer makelaars, elk geïdentificeerd met een
broker.id uniek. In de productie worden doorgaans 3, 6 of 9 makelaars gebruikt om fouttolerantie te garanderen. Makelaars verzorgen het schrijven
en het lezen van records, het bijhouden van logboeken op schijf en het repliceren tussen knooppunten.
Met Kafka 4.0 en de nieuwe manier van KRaft nemen één of meerdere makelaars ook de rol op zich controleur, het beheren van de clustermetagegevens (wie is de leider van welke partitie, welke makelaars zijn actief, enz.) via een intern Raft-consensuslogboek. Er is geen noodzaak meer van een afzonderlijk ZooKeeper-ensemble.
Onderwerp: De logische categorie van records
Un onderwerp is de logische naam waaronder producenten platen publiceren en consumenten ze lezen. Je kunt het zien als een thematisch kanaal:
ordini-effettuati, pagamenti-confermati, eventi-utente. Elk onderwerp heeft zijn eigen configuratie voor retentie,
aantal partities, replicatiefactor en compactiebeleid.
De onderwerpen zijn gepartitioneerd: elk onderwerp is verdeeld in N fysieke partities, verdeeld over de makelaars. Het is deze verdeling waardoor Kafka horizontaal schaalbaar is voor zowel schrijven als lezen.
Partitie: de eenheid van parallellisme en ordening
Una partitie het is een netjes en onveranderlijk logboek dat alleen kan worden toegevoegd. Elke record die naar een partitie wordt geschreven, ontvangt een gecompenseerd monotoon toenemend (0, 1, 2, ...). Sortering is gegarandeerd binnen de scheidingswand, niet tussen verschillende partities.
De distributie van records tussen partities wordt bepaald door partitie sleutel: Als de producent een sleutel opgeeft, de plaat gaat altijd naar dezelfde partitie (hash van het sleutelmodulusaantal partities), waardoor sortering voor die sleutel wordt gegarandeerd. Als de sleutel ontbreekt, Kafka gebruikt een sticky round-robin-strategie (batchrecords op dezelfde partitie voordat ze worden geroteerd).
# Creare un topic con 6 partizioni e replication factor 3
# (Kafka 4.0 con KRaft, niente --zookeeper flag)
kafka-topics.sh --create \
--bootstrap-server kafka1:9092 \
--topic ordini-effettuati \
--partitions 6 \
--replication-factor 3 \
--config retention.ms=604800000 \
--config min.insync.replicas=2
# Descrivere il topic per verificare la distribuzione
kafka-topics.sh --describe \
--bootstrap-server kafka1:9092 \
--topic ordini-effettuati
De output van --describe toont voor elke partitie: de leader-broker, de replica's en de gesynchroniseerde replica's (ISR —
In-gesynchroniseerde replica's). ISR's zijn de replica's die alle records van de leider hebben gerepliceerd: als de leider valt, kan er slechts één ISR zijn
gekozen als de nieuwe leider, waardoor er geen gegevensverlies optreedt.
De producent: platen schrijven in Kafka
Il producent het is de component die records over de onderwerpen publiceert. De producentenconfiguratie bepaalt de leveringsgaranties. De meest kritische eigenschappen zijn:
bootstrap.servers: lijst met makelaars voor de eerste verbinding (de client ontdekt de andere makelaars automatisch)key.serializerevalue.serializer: Sleutel en waarde serialiseren (StringSerializer, AvroSerializer, enz.)acks: hoeveel antwoordbevestigingen er moeten wachten voordat het schrijven als succesvol wordt beschouwd (0,1,all)retries: aantal pogingen bij tijdelijke foutlinger.ms: milliseconden om te wachten voordat een batch wordt verzonden (verhoogt de doorvoer ten koste van de latentie)batch.size: maximale batchgrootte in bytes (standaard: 16KB)
// Producer Java con configurazione production-ready
import org.apache.kafka.clients.producer.*;
import java.util.Properties;
public class OrdineProducer {
public static KafkaProducer<String, String> createProducer() {
Properties props = new Properties();
props.put("bootstrap.servers", "kafka1:9092,kafka2:9092,kafka3:9092");
props.put("key.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
// Garanzie di consegna: all = acks da tutti le ISR
props.put("acks", "all");
// Retry automatico con backoff
props.put("retries", 3);
props.put("retry.backoff.ms", 100);
// Batching per throughput
props.put("linger.ms", 5);
props.put("batch.size", 32768); // 32KB
// Compressione: riduce I/O di rete del 60-80%
props.put("compression.type", "snappy");
// Idempotenza: evita duplicati in caso di retry
props.put("enable.idempotence", true);
return new KafkaProducer<>(props);
}
public static void inviaOrdine(KafkaProducer<String, String> producer,
String ordineId, String payload) {
// La chiave (ordineId) determina la partizione target
ProducerRecord<String, String> record =
new ProducerRecord<>("ordini-effettuati", ordineId, payload);
// Invio asincrono con callback
producer.send(record, (metadata, exception) -> {
if (exception != null) {
System.err.println("Errore invio: " + exception.getMessage());
} else {
System.out.printf("Record inviato: topic=%s, partizione=%d, offset=%d%n",
metadata.topic(), metadata.partition(), metadata.offset());
}
});
}
}
Let op: acks en Throughput
Het verhogen van de garanties heeft een prijs: met acks=all e min.insync.replicas=2, verwacht de producent minimaal 2 antwoorden
het verslag hebben geschreven voordat u verdergaat. Dit voegt latentie toe (doorgaans 1-5 ms extra), maar zorgt er ook voor dat er geen gegevensverlies optreedt
als een makelaar direct na bevestiging afhaakt. Voor analytische systemen die enig verlies tolereren, acks=1 o acks=0
ze bieden een veel hogere doorvoer.
De consument: Records lezen van Kafka
De stemronde
De Kafka-consument gebruikt een template trekken: ontvangt geen pushberichten, maar vraagt deze via oproepen actief op bij de makelaar
poll(). Dit ontwerp zorgt ervoor dat de consument niet wordt overweldigd door een hoeveelheid berichten die zijn capaciteit te boven gaat
van verwerking.
// Consumer Java base con gestione degli offset manuale
import org.apache.kafka.clients.consumer.*;
import java.time.Duration;
import java.util.*;
public class OrdineConsumer {
public static void main(String[] args) {
Properties props = new Properties();
props.put("bootstrap.servers", "kafka1:9092,kafka2:9092,kafka3:9092");
props.put("group.id", "servizio-inventario");
props.put("key.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
// Comportamento alla prima lettura (nessun offset salvato per il gruppo)
// "earliest" = dall'inizio; "latest" = solo nuovi messaggi
props.put("auto.offset.reset", "earliest");
// Disabilitiamo il commit automatico per controllo preciso
props.put("enable.auto.commit", false);
// Timeout max per il join al consumer group (default: 45s)
props.put("session.timeout.ms", 30000);
try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props)) {
consumer.subscribe(List.of("ordini-effettuati"));
while (true) {
ConsumerRecords<String, String> records =
consumer.poll(Duration.ofMillis(100));
for (ConsumerRecord<String, String> record : records) {
System.out.printf("Offset: %d | Partizione: %d | Chiave: %s%n",
record.offset(), record.partition(), record.key());
// Elabora il record...
elaboraOrdine(record.value());
}
// Commit manuale DOPO l'elaborazione
// Garantisce at-least-once semantics
if (!records.isEmpty()) {
consumer.commitSync();
}
}
}
}
private static void elaboraOrdine(String payload) {
// logica di business...
}
}
Consumentengroep: het schaalmechanisme
Il consumenten groep het is het fundamentele mechanisme voor het parallel opschalen van de consumptie. Alle consumenten delen
hetzelfde group.id ze maken deel uit van dezelfde groep en verdelen de onderwerppartities. De regel is eenvoudig:
elke partitie kan aan slechts één verbruiker per groep tegelijk worden toegewezen.
Dit betekent dat het maximale aantal parallelle verbruikers in een groep gelijk is aan het aantal partities. Als je 6 partities hebt en je start 6 consumenten in dezelfde groep, ieder krijgt precies 1 partitie. Als u een 7e consument start, blijft deze inactief op stand-by (handig voor snelle failover).
Consumentengroep: schaalscenario's
- 1 verbruiker, 6 partities → een consument verwerkt alles, geen parallellisme
- 3 verbruikers, 6 partities → elke verbruiker beheert 2 partities parallel
- 6 verbruikers, 6 partities → maximaal parallellisme, 1 partitie per consument
- 9 verbruikers, 6 partities → 6 actief, 3 stand-by voor failover
- Twee verschillende groepen, hetzelfde onderwerp → elke groep ontvangt ALLE berichten onafhankelijk
Offsets: het positievolgmechanisme
L'gecompenseerd is een geheel getal dat op unieke wijze de locatie van een record binnen een partitie identificeert. De makelaar wijst de offset opeenvolgend toe aan elk geschreven record: het eerste record heeft een offset van 0, het tweede 1, enzovoort.
De consumentengroep slaat zijn eigen producten op toegezegde compensatie — d.w.z. de offset van het laatste succesvol verwerkte record —
in een speciaal intern Kafka-onderwerp genaamd __consumer_offsets. Dit is het uitgangspunt bij een doorstart
of consumentenfailover.
Het begrijpen van het verschil tussen deze offsets is van cruciaal belang voor de foutafhandeling:
- Offset logboekeind (LEO): de offset van het volgende record dat naar het logboek wordt geschreven (koppositie)
- Hoog watermerk (HW): de offset van het laatste record gerepliceerd over alle ISR's (de consument ziet alleen records ≤ HW)
- Huidige compensatie: de offset van het volgende record dat de consument zal lezen in de volgende poll()-aanroep
- Toegewijde compensatie: de offset die in het onderwerp is opgeslagen
__consumer_offsets(van waaruit opnieuw moet worden opgestart na een crash) - Consumentenvertraging: Verschil tussen LEO en Composed Offset, geeft aan hoeveel records de consument nog moet verwerken
# Controllare il consumer lag di un gruppo
kafka-consumer-groups.sh \
--bootstrap-server kafka1:9092 \
--describe \
--group servizio-inventario
# Output tipico:
# GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG
# servizio-inventario ordini-effettuati 0 1250 1280 30
# servizio-inventario ordini-effettuati 1 890 890 0
# servizio-inventario ordini-effettuati 2 2100 2105 5
# Resettare gli offset al principio (per reprocessing)
kafka-consumer-groups.sh \
--bootstrap-server kafka1:9092 \
--group servizio-inventario \
--topic ordini-effettuati \
--reset-offsets --to-earliest \
--execute
Replicatie: duurzaamheid en fouttolerantie
Elke partitie heeft een leider en nul of meer volgers (replica's). Producenten en consumenten communiceren altijd bij de leider. Volgers repliceren gegevens van de leider op een asynchrone maar over het algemeen snelle manier.
De groep volgers die ‘voldoende bijgewerkt’ zijn om leiders te worden, vormt de groepISR (gesynchroniseerde replica's).
Een volger wordt uit de ISR verwijderd als hij meer dan achterop raakt replica.lag.time.max.ms milliseconden (standaard: 30s).
Wanneer de leider valt, kiest de Kafka-controller de volger met de hoogste offset onder de ISR's als de nieuwe leider.
De combinatie van replication.factor e min.insync.replicas definieert de afweging tussen duurzaamheid en beschikbaarheid:
# Configurazione consigliata per produzione
# replication.factor=3 significa: 1 leader + 2 follower
# topic-level overrides
kafka-topics.sh --alter \
--bootstrap-server kafka1:9092 \
--topic ordini-effettuati \
--config min.insync.replicas=2
# Con questa configurazione:
# - acks=all: producer aspetta conferma da leader + 1 follower minimo
# - Se 2 broker su 3 sono down: il cluster rifiuta scritture (ma no data loss)
# - Se solo 1 broker è down: il cluster continua normalmente
# broker-level defaults in server.properties
default.replication.factor=3
min.insync.replicas=2
offsets.topic.replication.factor=3
transaction.state.log.replication.factor=3
Bewaarbeleid: Hoe lang de gegevens bewaard blijven
Records in Kafka worden verwijderd volgens beleid dat per onderwerp kan worden geconfigureerd. Er zijn twee hoofdmodi:
-
Op tijd gebaseerde retentie (
retention.ms): Records worden na een bepaalde periode uit hun tijdstempel verwijderd. Standaard: 604800000 ms = 7 dagen. Voor kritische onderwerpen zoals auditlogs worden veel hogere waarden (jaren) ingesteld. -
Retentie op basis van grootte (
retention.bytes): het logboek per partitie overschrijdt een bepaalde grootte niet. Wanneer de grootte de limiet overschrijdt, worden oudere segmenten verwijderd. -
Verdichting van houtblokken (
cleanup.policy=compact): in plaats van te verwijderen op tijd/grootte, behoudt Kafka alleen de laatste record voor elke sleutel. Ideaal voor statusonderwerpen (zoals databasetabellen gerepliceerd via CDC).
# Configurare retention per diversi use case
# Topic eventi real-time: retention breve, alta velocità
kafka-topics.sh --create \
--bootstrap-server kafka1:9092 \
--topic click-stream \
--partitions 12 \
--replication-factor 3 \
--config retention.ms=3600000 \ # 1 ora
--config retention.bytes=1073741824 # 1GB per partizione
# Topic log audit: retention lunga per compliance
kafka-topics.sh --create \
--bootstrap-server kafka1:9092 \
--topic audit-log \
--partitions 3 \
--replication-factor 3 \
--config retention.ms=31536000000 \ # 1 anno
--config compression.type=gzip
# Topic di stato con log compaction (es. profili utente)
kafka-topics.sh --create \
--bootstrap-server kafka1:9092 \
--topic profili-utente \
--partitions 6 \
--replication-factor 3 \
--config cleanup.policy=compact \
--config min.cleanable.dirty.ratio=0.5
Consumentenpython: een praktisch voorbeeld
Het Kafka-ecosysteem ondersteunt vele talen. Hier is een Python-voorbeeld waarbij de bibliotheek wordt gebruikt confluent-kafka
(de officiële Confluent-binding gebaseerd op librdkafka, veel performanter dan kafka-python):
# pip install confluent-kafka
from confluent_kafka import Consumer, KafkaError, KafkaException
import json
import signal
import sys
TOPIC = "ordini-effettuati"
GROUP_ID = "servizio-analytics-py"
config = {
"bootstrap.servers": "kafka1:9092,kafka2:9092",
"group.id": GROUP_ID,
"auto.offset.reset": "earliest",
"enable.auto.commit": False,
"session.timeout.ms": 30000,
"max.poll.interval.ms": 300000, # 5 minuti per elaborazioni lente
}
consumer = Consumer(config)
running = True
def graceful_shutdown(signum, frame):
global running
running = False
signal.signal(signal.SIGINT, graceful_shutdown)
signal.signal(signal.SIGTERM, graceful_shutdown)
try:
consumer.subscribe([TOPIC])
print(f"Consumer avviato, gruppo: {GROUP_ID}")
while running:
msg = consumer.poll(timeout=1.0)
if msg is None:
continue
if msg.error():
if msg.error().code() == KafkaError._PARTITION_EOF:
# Raggiunta la fine della partizione, aspetta nuovi messaggi
print(f"Raggiunto EOF: {msg.topic()} [{msg.partition()}] offset {msg.offset()}")
elif msg.error():
raise KafkaException(msg.error())
else:
ordine = json.loads(msg.value().decode("utf-8"))
print(f"Ricevuto ordine {ordine['id']} da partizione {msg.partition()}")
# Elabora l'ordine...
elabora_ordine(ordine)
# Commit manuale dopo elaborazione riuscita
consumer.commit(asynchronous=False)
finally:
consumer.close()
print("Consumer chiuso correttamente")
def elabora_ordine(ordine):
# Logica di business...
pass
Aanbevolen architectuur: hoeveel partities?
Een van de meest voorkomende vragen voor degenen die met Kafka beginnen, is: hoeveel partities moeten er voor een onderwerp worden gemaakt? Het antwoord hangt af van verschillende factoren:
- Maximaal parallellisme van de consumentengroep: het aantal partities is het maximale aantal parallelle verbruikers. Schat het aantal consumenten dat u op het hoogtepunt verwacht te hebben.
- Doeldoorvoer: Elke partitie kan doorgaans een schrijfsnelheid van 10-50 MB/s aan (afhankelijk van de schijf). Deel de totale doorvoer door dit getal om het minimaal benodigde aantal partities te verkrijgen.
- Sorteren: als u de bestelling voor een bepaalde sleutel moet garanderen (bijvoorbeeld alle evenementen van dezelfde klant), die client komt altijd op dezelfde partitie terecht. Meer partities = betere verdeling van de belasting voor verschillende sleutels.
- Geheugenoverhead: Elke partitie vereist geheugen in de broker (~1-2 MB overhead). Met in totaal 100K partities, het begint zijn tol te eisen.
Praktische regel voor partities
Een benaderende formule: max(throughput_MB_s / 10, consumer_max_paralleli). Voor de meeste toepassingen is
6, 12 of 24 partities zijn redelijke waarden. Met Kafka kun je later partities laten groeien, maar
om ze niet te verkleinen: Plan met een kleine marge.
Logboekverdichting: het gebruiksvoorbeeld voor staatsonderwerpen
La verdichting van houtblokken is een geavanceerde functie van Kafka die de semantiek volledig verandert retentie: in plaats van records te verwijderen op basis van tijd of grootte, bewaart Kafka alleen delaatste record voor elke sleutel. Tijdens het compactieproces worden alle oudere records met dezelfde sleutel verwijderd.
Dit maakt gecomprimeerde onderwerpen ideaal voor het vertegenwoordigen van de huidige staat van entiteiten: gebruikersprofielen, actuele prijzen, systeemconfiguraties, inventaris. Een consument die verbinding maakt met een onderwerp voor het eerst gecomprimeerd kan het de volledige staat reconstrueren door alle aanwezige records te lezen (één per sleutel), zonder dat u de hele geschiedenis van gebeurtenissen hoeft te lezen.
Een record met waarde null (“tombstone record”) is de manier om een sleutel uit een onderwerp te verwijderen
gecomprimeerd: na het comprimeren verdwijnt de sleutel zelf ook uit het logboek.
# Creare un topic con log compaction
kafka-topics.sh --create \
--bootstrap-server kafka1:9092 \
--topic profili-utente \
--partitions 6 \
--replication-factor 3 \
--config cleanup.policy=compact \
--config min.cleanable.dirty.ratio=0.5 \
--config segment.ms=86400000 \
--config delete.retention.ms=86400000
# cleanup.policy=compact: abilita compaction
# min.cleanable.dirty.ratio=0.5: compatta quando >50% del log e' "dirty"
# segment.ms=86400000: crea un nuovo segmento ogni 24h
# delete.retention.ms: quanto tenere i tombstone record prima di eliminarli
# Inviare un aggiornamento profilo (chiave = userId)
kafka-console-producer.sh \
--bootstrap-server kafka1:9092 \
--topic profili-utente \
--property parse.key=true \
--property key.separator=:
# Digita: user123:{"nome":"Mario","email":"mario@example.com","eta":30}
# Digita: user456:{"nome":"Anna","email":"anna@example.com","eta":25}
# Digita: user123:{"nome":"Mario","email":"mario.rossi@example.com","eta":31}
# Dopo compaction, nel topic rimane solo l'ultima riga per user123
Kafka internals-onderwerp: __consumer_offsets en __transaction_state
Kafka gebruikt intern speciale onderwerpen om zijn staat te beheren. Als u ze kent, begrijpt u beter hoe ze werken van het systeem en het oplossen van problemen:
-
__consumer_offsets: slaat de vastgelegde compensaties van elke consumentengroep op. Het heeft standaard 50 partities (offsets.topic.num.partitions). De consumentengroep is toegewezen naar een partitie via hash van de group.id. Als dit onderwerp replicatieproblemen heeft, kunnen consumentengroepen ze slagen er niet in om compensaties te plegen. -
__transaction_state: beheert de status van lopende transacties. Gebruikt door de Kafka transactionele API om exact één keer semantiek te garanderen. Het heeft standaard 50 partities. -
@metadata(Alleen KRaft): het metagegevenslogboek van de quorumcontroller. Bevat alle clustermetagegevens (onderwerpen, partities, makelaars, ACL's, configuraties). Alleen intern toegankelijk voor de controllers.
# Ispezionare il topic __consumer_offsets (advanced troubleshooting)
# ATTENZIONE: operazione read-only, non modificare mai questi topic
kafka-console-consumer.sh \
--bootstrap-server kafka1:9092 \
--topic __consumer_offsets \
--formatter "kafka.coordinator.group.GroupMetadataManager\$OffsetsMessageFormatter" \
--from-beginning \
--max-messages 20
# Output esempio:
# [servizio-inventario,ordini-effettuati,0]::OffsetAndMetadata(offset=1250, ...)
# [servizio-inventario,ordini-effettuati,1]::OffsetAndMetadata(offset=890, ...)
# Elencare tutti i consumer group attivi
kafka-consumer-groups.sh \
--bootstrap-server kafka1:9092 \
--list
# Dettaglio di un gruppo specifico
kafka-consumer-groups.sh \
--bootstrap-server kafka1:9092 \
--group servizio-inventario \
--describe \
--state # include stato del gruppo (Stable, Rebalancing, Empty, Dead)
Berichtkop en tijdstempel
Elk Kafka-record heeft een precieze structuur:
- Sleutel (optioneel): bepaalt de doelpartitie, geserialiseerd in bytes
- Waarde: de berichtlading, geserialiseerd in bytes
- Tijdstempel: creatietijd aan de producentenkant (
CreateTime) of opname aan de makelaarzijde (LogAppendTime), configureerbaar - Kopteksten: sleutel-waardeparen voor metagegevens (correlatie-ID, gebeurtenistype, schemaversie, enz.)
- Partitie + Offset: toegewezen door de makelaar op het moment van schrijven
// Aggiungere headers a un ProducerRecord Java
ProducerRecord<String, String> record = new ProducerRecord<>(
"ordini-effettuati",
ordineId,
payload
);
// Headers per tracciabilità e versioning
record.headers()
.add("correlation-id", UUID.randomUUID().toString().getBytes())
.add("schema-version", "2".getBytes())
.add("source-service", "checkout-service".getBytes())
.add("event-type", "OrdineCreato".getBytes());
producer.send(record);
Docker Compose: snelle start voor lokale ontwikkeling
Om lokaal met Kafka te gaan experimenteren zonder met complexe configuraties te maken te krijgen, de snelste manier is om Docker Compose te gebruiken met de officiële Apache Kafka 4.0-afbeelding:
# docker-compose.yml minimale per sviluppo locale (single-node KRaft)
version: "3.9"
services:
kafka:
image: apache/kafka:4.0.0
container_name: kafka-local
ports:
- "9092:9092"
environment:
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: "broker,controller"
KAFKA_LISTENERS: "PLAINTEXT://kafka-local:9092,CONTROLLER://kafka-local:9093"
KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://localhost:9092"
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT"
KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka-local:9093"
KAFKA_INTER_BROKER_LISTENER_NAME: "PLAINTEXT"
CLUSTER_ID: "local-dev-cluster-id-001"
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
# Avvio:
# docker-compose up -d
#
# Verifica:
# docker exec kafka-local kafka-topics.sh --bootstrap-server localhost:9092 --list
Samenvatting: De fundamentele concepten
Nadat we de interne structuur van Kafka hebben onderzocht, volgt hier een samenvatting van de belangrijkste concepten die we moeten onthouden:
- Makelaar: clusterknooppunt, beheert schijflogboeken en replicatie
- Onderwerpen: logische categorie records, verdeeld in partities
- Partitie: gesorteerd logbestand met alleen toevoegen, eenheid van parallellisme; bestellen gegarandeerd alleen binnen
- Offset: progressieve positie van elke record in een partitie
- Consumentengroep: schaalmechanisme; elke partitie is slechts aan één consument per groep toegewezen
- ISR: set bijgewerkte replica's, waaruit de nieuwe leider wordt gekozen in geval van een fout
- Consumentenvertraging: kritische gezondheidsindicator, verschil tussen LEO en vastgelegde compensatie
- Behoud: Records blijven configureerbaar, ze worden na consumptie niet verwijderd
Volgende stappen in de serie
Nu je een solide basis hebt, gaan de volgende artikelen in de serie dieper in op meer geavanceerde aspecten:
- Artikel 2 – KRaft in Kafka 4.0: hoe de nieuwe controller werkt zonder ZooKeeper, het migratieproces van Kafka 3.x en de operationele voordelen in de productie.
-
Artikel 3 – Geavanceerde producent en consument: de gedetailleerde configuratie van
acks,retries,max.in.flight.requestsen de idempotente producent voor precies één keer garanties op producentenniveau. - Artikel 4 – Exactly-Once-semantiek: Kafka-transacties voor atomaire schrijfsels over meerdere onderwerpen, de transactiecoördinator en de implicaties voor de doorvoer.
Link met andere series
- Waarneembaarheid en OpenTelemetrie: Hoe u een Kafka-applicatie kunt instrumenteren met OpenTelemetry om de verspreiding van gebeurtenissen tussen producenten en consumenten te volgen.
- Platformtechniek: Kafka als fundamenteel onderdeel van een intern ontwikkelaarsplatform voor gebeurtenisgestuurde communicatie tussen teams.
- PostgreSQL-AI: CDC-patroon (Change Data Capture) met Debezium om PostgreSQL te synchroniseren in realtime naar Kafka, het onderwerp van artikel 7 van deze serie.







