Fundamentele Apache Kafka: subiecte, partiții, compensații și grupuri de consumatori
Kafka nu este doar o coadă de mesaje: este un jurnal de comitere distribuit conceput pentru a susține milioane de evenimente pe secundă cu durabilitate garantată. În acest ghid fundamental, descoperiți structura internă a subiectelor și partițiilor și cum funcționează compensațiile de urmărire locația precisă și de ce grupul de consumatori este mecanismul cheie pentru scalarea consumului în paralel.
De ce Kafka este diferit de o Coda tradițională
Când proiectați un sistem distribuit care trebuie să gestioneze fluxurile de evenimente în timp real, prima tentație este să folosiți o coadă de mesaje clasică. precum RabbitMQ sau ActiveMQ. Aceste soluții funcționează bine pentru scenarii simple, dar au o limitare structurală cheie: odată consumatorul consumat mesajul, mesajul este șters. Nu există posibilitatea de a o reciti, de a avea mai mulți consumatori independenți care o prelucrează diferit, sau pentru a relua întreaga istorie a evenimentelor.
Apache Kafka s-a născut în 2011 în LinkedIn cu o filozofie radical diferită: mesajele (numite înregistra) sunt scrise în a jurnal numai pentru adăugare și rămâne acolo pentru o perioadă configurabilă (implicit: 7 zile). Diferiți consumatori pot citi uneori aceleași înregistrări diferite, fiecare ținând evidența poziției sale prin intermediuloffset. Acest model îl transformă pe Kafka în mult mai mult decât o coadă: devine cel sursa adevarului pentru întregul istoric al evenimentelor din sistemul dumneavoastră.
Kafka în 2026: numere cheie
- Folosit de peste 80% dintre companiile Fortune 500 pentru cazuri de utilizare în flux
- Kafka 4.0 (martie 2025) a eliminat definitiv ZooKeeper, trecând la KRaft
- Debit teoretic: Peste 1 milion de mesaje/secundă pentru brokeri (hardware de marfă)
- Confluent Cloud: Kafka gestionat disponibil pe AWS, GCP, Azure cu latență < 10 ms p99
- Ecosistem: peste 200 de conectori prin Kafka Connect, Kafka Streams, integrare Apache Flink
Modelul fundamental: broker, subiect și partiție
Broker: Nodul Cluster
Un broker este pur și simplu un server Kafka. Un cluster Kafka este compus din unul sau mai mulți brokeri, fiecare identificat prin a
broker.id unic. În producție, se folosesc de obicei 3, 6 sau 9 brokeri pentru a garanta toleranța la erori. Brokerii se ocupă de scriere
și citirea înregistrărilor, menținerea jurnalelor pe disc și replicarea între noduri.
Cu Kafka 4.0 și noul mod KRaft, unul sau mai mulți brokeri își asumă și rolul de controlor, gestionând metadatele clusterului (cine este liderul cărei partiții, ce brokeri sunt activi etc.) printr-un jurnal intern de consens Raft. Nu mai este nevoie a unui ansamblu ZooKeeper separat.
Subiect: Categoria logică a înregistrărilor
Un subiect este numele logic sub care producătorii publică înregistrările și consumatorii le citesc. Vă puteți gândi la el ca pe un canal tematic:
ordini-effettuati, pagamenti-confermati, eventi-utente. Fiecare subiect are propria configurație pentru reținere,
numărul de partiții, factorul de replicare și politicile de compactare.
Subiectele sunt compartimentat: fiecare subiect este împărțit în N partiții fizice, distribuite între brokeri. Este această distribuție ceea ce face ca Kafka să fie scalabil pe orizontală atât pentru scris, cât și pentru citit.
Despărțire: Unitatea paralelismului și ordonării
Una compartimentare este un jurnal ordonat și imuabil numai pentru adăugare. Fiecare înregistrare scrisă pe o partiție primește un offset crescător monoton (0, 1, 2, ...). Sortarea este garantată in interiorul partitiei, nu între diferite partiții.
Distribuția înregistrărilor între partiții este determinată de cheie de partiție: Dacă producătorul specifică o cheie, înregistrarea merge întotdeauna la aceeași partiție (hash al modulului cheii, numărul de partiții), garantând sortarea pentru acea cheie. Dacă cheia lipsește, Kafka folosește o strategie round-robin (înregistrări de lot pe aceeași partiție înainte de rotație).
# 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
Ieșirea de --describe afișează pentru fiecare partiție: brokerul lider, replicile și replicile în sincronizare (ISR —
Replici în sincronizare). ISR-urile sunt replicile care au replicat toate înregistrările liderului: dacă liderul cade, un singur ISR poate fi
ales ca noul lider, asigurând nicio pierdere de date.
Producătorul: Scrierea de discuri în Kafka
Il producător este componenta care publică înregistrări pe subiecte. Configurația producătorului determină garanțiile de livrare. Cele mai critice proprietăți sunt:
bootstrap.servers: lista de brokeri pentru conexiunea initiala (clientul descopera automat ceilalti brokeri)key.serializerevalue.serializer: Cum să serializeze cheia și valoarea (StringSerializer, AvroSerializer etc.)acks: câte confirmări de răspuns să așteptați înainte de a considera scrierea reușită (0,1,all)retries: numărul de încercări în caz de eroare temporarălinger.ms: milisecunde de așteptat înainte de a trimite un lot (mărește debitul în detrimentul latenței)batch.size: dimensiunea maximă a lotului în octeți (implicit: 16 KB)
// 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());
}
});
}
}
Atenție: ack și Throughput
Creșterea garanțiilor are un cost: cu acks=all e min.insync.replicas=2, producătorul așteaptă cel puțin 2 răspunsuri
au scris dosarul înainte de a continua. Acest lucru adaugă latență (de obicei 1-5 ms suplimentar), dar asigură și nicio pierdere de date
dacă un broker scade imediat după confirmare. Pentru sistemele analitice care tolerează anumite pierderi, acks=1 o acks=0
oferă un randament mult mai mare.
Consumatorul: Citirea înregistrărilor de la Kafka
Bucla de sondare
Consumatorul Kafka folosește un șablon Trage: nu primește mesaje push, dar le solicită în mod activ de la broker prin apeluri
poll(). Acest design asigură că consumatorul nu este copleșit de un volum de mesaje peste capacitatea sa
de prelucrare.
// 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...
}
}
Grupul de consumatori: Mecanismul de scalare
Il grup de consumatori este mecanismul fundamental de scalare a consumului în paralel. Toți consumatorii împărtășesc
la fel group.id fac parte din același grup și împart partițiile de subiecte. Regula este simplă:
fiecare partiție poate fi atribuită unui singur consumator per grup la un moment dat.
Aceasta înseamnă că numărul maxim de consumatori paraleli dintr-un grup este egal cu numărul de partiții. Dacă aveți 6 partiții și porniți 6 consumatori în același grup, fiecare primește exact 1 partiție. Dacă porniți un al șaptelea consumator, acesta va rămâne inactiv în standby (util pentru failover rapid).
Grup de consumatori: scenarii de scalare
- 1 consumator, 6 partitii → un consumator procesează totul, fără paralelism
- 3 consumatori, 6 partitii → fiecare consumator gestioneaza 2 partitii in paralel
- 6 consumatori, 6 partitii → paralelism maxim, 1 partiție per consumator
- 9 consumatori, 6 partiții → 6 active, 3 în standby pentru failover
- Două grupuri distincte, același subiect → fiecare grup primește TOATE mesajele în mod independent
Compensații: Mecanismul de urmărire a poziției
L'offset este un număr întreg care identifică în mod unic locația unei înregistrări într-o partiție. Brokerul atribuie offset-ul secvenţial fiecărei înregistrări scrise: prima înregistrare are un offset de 0, a doua 1 şi aşa mai departe.
Grupul de consumatori își păstrează propriile sale compensare comisă — adică decalajul ultimei înregistrări procesate cu succes —
într-un subiect intern special Kafka numit __consumer_offsets. Acesta este punctul de pornire în cazul unei reporniri
sau failoverul consumatorului.
Înțelegerea diferenței dintre aceste decalaje este critică pentru tratarea erorilor:
- Compensarea sfârșitului jurnalului (LEO): compensarea următoarei înregistrări care va fi scrisă în jurnal (poziția capului)
- Filigran ridicat (HW): compensarea ultimei înregistrări replicate în toate ISR-urile (consumatorul vede doar înregistrările ≤ HW)
- Offset curent: compensarea următoarei înregistrări pe care consumatorul o va citi în următorul apel poll().
- Compensare comisă: offset-ul salvat în subiect
__consumer_offsets(de la care să reporniți după un accident) - Întârzierea consumatorului: Diferența dintre LEO și Committed Offset, indică câte înregistrări trebuie să proceseze consumatorul
# 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
Replicare: durabilitate și toleranță la erori
Fiecare partiție are un lider și zero sau mai mult urmași (replici). Producătorii și consumatorii comunică mereu cu liderul. Adepții reproduce datele de la lider într-un mod asincron, dar în general rapid.
Setul de adepți care sunt „suficient de actualizați” pentru a deveni lideri formeazăISR (replici în sincronizare).
Un adept este eliminat din ISR dacă rămâne în urmă cu mai mult de replica.lag.time.max.ms milisecunde (implicit: 30s).
Când liderul cade, controlorul Kafka alege adeptul cu cel mai mare decalaj dintre ISR ca noul lider.
Combinația de replication.factor e min.insync.replicas definește compromisul dintre durabilitate și disponibilitate:
# 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
Politica de păstrare: Cât timp rămân datele
Înregistrările din Kafka sunt eliminate conform politicilor care pot fi configurate pe subiect. Există două moduri principale:
-
Retentie bazata pe timp (
retention.ms): Înregistrările sunt șterse după o anumită perioadă din marcajul de timp. Implicit: 604800000ms = 7 zile. Pentru subiectele critice, cum ar fi jurnalele de audit, sunt setate valori mult mai mari (ani). -
Retenție bazată pe dimensiune (
retention.bytes): jurnalul per partiție nu depășește o anumită dimensiune. Când dimensiunea depășește limita, segmentele mai vechi sunt șterse. -
Compactarea buștenilor (
cleanup.policy=compact): în loc să șterge după timp/dimensiune, Kafka păstrează doar ultima înregistrare pentru fiecare cheie. Ideal pentru subiecte de stat (cum ar fi tabelele de baze de date replicate prin 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
Consumer Python: Un exemplu practic
Ecosistemul Kafka acceptă multe limbi. Iată un exemplu Python folosind biblioteca confluent-kafka
(legarea oficială Confluent bazată pe librdkafka, mult mai performantă decât 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
Arhitectură recomandată: Câte partiții?
Una dintre cele mai frecvente întrebări pentru cei care încep cu Kafka este: câte partiții să creați pentru un subiect? Răspunsul depinde de mai mulți factori:
- Paralelismul maxim al grupului de consumatori: numărul de partiții este numărul maxim de consumatori paraleli. Estimați numărul de consumatori pe care vă așteptați să-i aveți la vârf.
- Debitul țintă: Fiecare partiție poate gestiona de obicei 10-50 MB/s scriere (depinde de disc). Împărțiți debitul total la această cifră pentru a obține numărul minim de partiții necesare.
- Triere: dacă trebuie să garantați comanda pentru o anumită cheie (de exemplu, toate evenimentele aceluiași client), acel client va ajunge întotdeauna pe aceeași partiție. Mai multe partiții = o distribuție mai bună a încărcării pentru diferite chei.
- Memorie deasupra capului: Fiecare partiție necesită memorie în broker (aproximativ 1-2 MB). Cu 100K partiții totale, începe să ia o taxă.
Regulă practică pentru partiții
O formulă aproximativă: max(throughput_MB_s / 10, consumer_max_paralleli). Pentru majoritatea aplicațiilor,
6, 12 sau 24 de partiții sunt valori rezonabile. Kafka vă permite să creșteți partițiile mai târziu, dar
să nu le diminueze: Plan cu o mică marjă.
Compactarea jurnalului: cazul de utilizare pentru subiectele de stat
La compactare bușteni este o caracteristică avansată a lui Kafka care schimbă complet semantica reținere: în loc să șterge înregistrările după timp sau dimensiune, Kafka păstrează doar fișierulultima înregistrare pentru fiecare cheie. Toate înregistrările mai vechi cu aceeași cheie sunt șterse în timpul procesului de compactare.
Acest lucru face ca subiectele compacte să fie ideale pentru reprezentarea starea actuală de entitate: profiluri de utilizator, prețuri curente, configurații de sistem, inventar. Un consumator care se conectează la un subiect compactat pentru prima dată poate reconstrui starea completă citind toate înregistrările prezente (una pe tastă), fără a fi nevoie să citiți întreaga istorie a evenimentelor.
Un record cu valoare null („înregistrarea piatră funerară”) este modalitatea de a șterge o cheie dintr-un subiect
compactat: după compactare, cheia însăși dispare din buștean.
# 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
Subiectul intern Kafka: __consumer_offsets și __transaction_state
Kafka folosește în interior subiecte speciale pentru a-și gestiona starea. Cunoașterea lor vă ajută să înțelegeți cum funcționează a sistemului și pentru a depana:
-
__consumer_offsets: stochează compensațiile angajate ale fiecărui grup de consumatori. Are 50 de partiții în mod implicit (offsets.topic.num.partitions). Se desemnează grupul de consumatori la o partiție prin hash a grupului.id. Dacă acest subiect are probleme de replicare, grupurile de consumatori nu reușesc să comită compensații. -
__transaction_state: gestionează starea tranzacțiilor în curs. Folosit de API-ul tranzacțional Kafka pentru a garanta o semantică exactă. Are 50 de partiții în mod implicit. -
@metadata(Numai KRaft): jurnalul de metadate al controlerului de cvorum. Conține toate metadatele clusterului (subiecte, partiții, brokeri, ACL-uri, configurații). Accesibil doar intern pentru controlere.
# 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)
Antetul mesajului și marcajul de timp
Fiecare înregistrare Kafka are o structură precisă:
- Cheie (opțional): determină partiția țintă, serializată în octeți
- Valoare: sarcina utilă a mesajului, serializat în octeți
- Marca temporală: timpul de creare din partea producătorului (
CreateTime) sau ingestie de partea brokerului (LogAppendTime), configurabil - Anteturi: perechi cheie-valoare pentru metadate (ID de corelare, tipul evenimentului, versiunea schemei etc.)
- Partiție + Offset: atribuit de broker la momentul scrierii
// 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: pornire rapidă pentru dezvoltare locală
Pentru a începe să experimentați cu Kafka la nivel local, fără a vă ocupa de configurații complexe, cel mai rapid mod este să utilizați Docker Compose cu imaginea oficială Apache Kafka 4.0:
# 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
Rezumat: Conceptele fundamentale
După ce am explorat structura internă a lui Kafka, iată un rezumat al conceptelor cheie de memorat:
- Broker: nod cluster, gestionează jurnalele discului și replicarea
- Subiecte: categorie logică de înregistrări, împărțite în partiții
- Partiție: jurnal sortat numai pentru adăugare, unitate de paralelism; comanda garantata doar in interior
- Offset: poziția progresivă a fiecărei înregistrări într-o partiție
- Grupul de consumatori: mecanism de scalare; fiecare partiție alocată unui singur consumator per grup
- ISR: set de replici actualizate, din care este ales noul lider în caz de greșeală
- Întârzierea consumatorului: indicator critic de sănătate, diferența dintre LEO și compensarea comisă
- Retenţie: Înregistrările rămân configurabile, nu sunt șterse după consum
Următorii pași din serie
Acum că aveți o bază solidă, următoarele articole din serie se aprofundează în aspecte mai avansate:
- Articolul 2 – KRaft în Kafka 4.0: cum funcționează noul controler fără ZooKeeper, procesul de migrare de la Kafka 3.x și beneficiile operaționale în producție.
-
Articolul 3 – Producător și Consumator avansat: configurația detaliată a
acks,retries,max.in.flight.requestsiar producătorul idempotent pentru garanții exact-o dată la nivel de producător. - Articolul 4 – Semantica Exact O dată: tranzacții Kafka pentru scrieri atomice pe mai multe subiecte, coordonatorul tranzacției și implicațiile asupra debitului.
Legătură cu alte serii
- Observabilitate și OpenTelemetry: Cum se instrumentează o aplicație Kafka cu OpenTelemetry pentru a urmări propagarea evenimentelor între producători și consumatori.
- Ingineria platformei: Kafka ca componentă fundamentală a unei platforme pentru dezvoltatori interni pentru comunicarea bazată pe evenimente între echipe.
- AI PostgreSQL: model CDC (Change Data Capture) cu Debezium pentru a sincroniza PostgreSQL lui Kafka în timp real, subiectul articolului 7 din această serie.







