60-Day Kafka 4 Learning Plan · Week 1 — Foundations
Sources: Kafka: The Definitive Guide Ch.6 · kafka.apache.org/43 — KRaft docs
Goal
Understand how Kafka 4 manages itself without ZooKeeper — and why that matters for every deployment decision.
1. Why KRaft? The ZooKeeper problem
Old architecture (Kafka ≤ 3.x)
Broker 1 (controller) ─┐
Broker 2 ─┼──► ZooKeeper ensemble (3 separate nodes)
Broker 3 ─┘ stores: topics, partitions, ISR, ACLs, broker IDs
Problems with ZooKeeper:
- 2 systems to deploy, monitor, and upgrade
- Metadata lag between ZooKeeper and Kafka brokers
- Hard ceiling of ~200k partitions per cluster
- Slow controller failover (seconds, not milliseconds)
- Complex rolling upgrades across two systems
New architecture (Kafka 4 — KRaft only)
┌────────────────────────────────────────────────────────────────┐
│ One unified Kafka cluster — metadata managed internally │
│ │
│ [Controller 1] [Controller 2] [Controller 3] [Brokers] │
│ ACTIVE LEADER hot standby hot standby N nodes │
└────────────────────────────────────────────────────────────────┘
KRaft benefits:
- ✓ One system — simpler ops, no ZooKeeper to monitor or fail
- ✓ Metadata always inside Kafka — no lag, strongly consistent
- ✓ Millions of partitions per cluster (vs ~200k with ZooKeeper)
- ✓ Controller failover in milliseconds vs seconds
2. How Raft consensus works
Every controller node is always in one of 3 states:

Leader election — 4 steps
1. Heartbeat 2. Timeout 3. Vote request 4. Majority wins
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Leader │ ───► │ No hbeat │ ───► │ Candidate│ ───► │ New │
│ pings │ │ follower │ │ asks │ │ leader │
│ followers│ │→candidate│ │ peers │ │ elected │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
Quorum rules:
- 3 controllers → need 2 votes to elect leader
- 5 controllers → need 3 votes to elect leader
- Elections use term numbers — higher term always wins, prevents split-brain scenarios
3. The __cluster_metadata log
Every cluster change is appended as a record to this special internal topic:
offset 0 offset 1 offset 2 offset 3 offset 4 offset 5 offset 6 →
┌───────────┬─────────────┬─────────────┬────────────┬──────────────┬───────────┬────────────┐
│ BrokerReg │ TopicCreate │ PartAssign │ ISRChange │ ConfigChange │ ACLUpdate │ next... │
└───────────┴─────────────┴─────────────┴────────────┴──────────────┴───────────┴────────────┘
What gets stored:

Snapshots: Periodically the full metadata state is compacted into a snapshot file on disk. New controllers can bootstrap from the latest snapshot without replaying the entire log from offset 0.
4. KRaft process roles and deployment modes
Set process.roles in server.properties:

Production recommendation:
- 3 dedicated controller nodes + N broker nodes
- Always use an odd number of controllers (3 or 5)
- Controller nodes need: 5 GB RAM + 5 GB disk for the metadata log
- Do not use
broker,controllercombined mode for large production workloads
5. How metadata flows — full picture
Client Active Controller Follower Ctrls Brokers
│ │ │ │
│── 1. create topic ────►│ │ │
│ │── 2. replicate ───►│ │
│ │◄─────── quorum ack─┤ │
│ │── 3. committed ────┤ │
│ │ │ │
│ │◄──────────── 4. brokers fetch metadata ◄─┤
│ │ │
│ │──────────── 5. metadata applied ──►│
│ topic now live │
6. Useful KRaft commands
# Check quorum status
kafka-metadata-quorum.sh --bootstrap-controller :9093 describe --status
# Describe metadata log replication
kafka-metadata-quorum.sh --bootstrap-controller :9093 describe --replication
# Browse metadata shell (interactive)
kafka-metadata-shell.sh --directory /var/kafka-logs/__cluster_metadata-0
# Generate cluster ID (once, before formatting storage)
kafka-storage.sh random-uuid
# Format storage on each node (run once per node)
kafka-storage.sh format \
--config /etc/kafka/server.properties \
--cluster-id <YOUR_CLUSTER_ID>
TL;DR
KRaft replaces ZooKeeper by running the Raft consensus algorithm inside Kafka itself. A quorum of controller nodes (3 recommended) elect one active leader that handles all metadata writes. Every cluster change — topic creation, partition assignment, ISR update, ACL change — is appended to __cluster_metadata, replicated to follower controllers for quorum acknowledgment, then fetched by brokers. Snapshots enable fast bootstrap. Kafka 4 is KRaft-only: ZooKeeper is permanently removed.
Support me through GitHub Sponsors.
Next
➡️ Day 4 — Local setup: Docker Compose + Spring Boot 3.x + Kafka 4 (KRaft mode)
Resources
- 📘 Kafka: The Definitive Guide — Chapter 6 (Reliable Data Delivery)
- 🌐 kafka.apache.org/43/documentation/kraft
- 🌐 KIP-500: Replace ZooKeeper with a self-managed metadata quorum
- 🌐 Conduktor — Understanding KRaft Mode