Kafka Controller: KRaft Quorum vs ZooKeeper
Fast recall
Quick revision
Core answer
__cluster_metadata topic. KRaft enables faster failover, single-binary operations, and clusters with millions of partitions instead of tens of thousands.Whether you understand the role of the controller in cluster coordination and the architectural shift from ZooKeeper to KRaft
Thinking the controller is involved in every produce/consume request — it only handles metadata changes (leader elections, topic creation, ISR updates), not data path
Explain why the ZooKeeper model bottlenecked at ~200K partitions, how KRaft's metadata log scales differently, and the migration path for existing ZK clusters
Interview-ready guide
Interview answer
The controller is the broker responsible for cluster coordination — it elects partition leaders when a broker dies, updates the ISR, and propagates topic creation and ACL changes. Importantly, the controller is not in the data path; it doesn't touch produce or consume traffic.
The historical model used ZooKeeper:
- Brokers registered themselves as ephemeral znodes; the controller was elected by being the first to create
/controllerin ZooKeeper - Cluster metadata — brokers, topics, partition assignments, configs — lived in ZK
- The downside was operating two distributed systems and a hard scaling ceiling around 200,000 partitions per cluster, with controller failover that took minutes because the new controller had to reload all metadata from ZK
KRaft replaces ZooKeeper:
- A small set of brokers, typically 3 or 5, are designated as
controller.quorum.votersand run Raft consensus among themselves - Cluster metadata is stored as an append-only log in the internal
__cluster_metadatatopic - Every other broker tails that log to learn cluster state, the same way ordinary consumers tail any topic
- Failover is sub-second because every voter already has the metadata in memory; clusters now scale comfortably to millions of partitions
Operational impact:
- One distributed system instead of two — no separate ZK to deploy, monitor, patch, secure, and back up
- Faster broker startup, faster controller failover, simpler single-binary deployments
- Kafka 4.0 removed ZooKeeper support entirely; existing ZK clusters need to use the KIP-866 migration path
For any new cluster I default to KRaft with a dedicated 3-node controller quorum separate from the data brokers, because it gives the cleanest operational model and matches where the project is going.
Kafka Controller: KRaft Quorum vs ZooKeeper
Direct Answer
The controller is the broker responsible for partition leader elections, ISR updates, and propagating cluster metadata. In legacy ZooKeeper mode, a single controller is elected via ZooKeeper, and metadata is stored in ZK znodes. In KRaft mode (production-ready since 3.3, default in 3.5+), Kafka removes ZooKeeper entirely: a small set of dedicated controller nodes form a Raft consensus quorum and store metadata in an internal __cluster_metadata topic. KRaft enables faster failover, single-binary operations, and clusters with millions of partitions instead of tens of thousands.
Code Example
Legacy ZooKeeper-based broker (server.properties):
broker.id=1
listeners=PLAINTEXT://:9092
log.dirs=/var/lib/kafka/logs
# Required: external ZooKeeper ensemble
zookeeper.connect=zk1:2181,zk2:2181,zk3:2181
zookeeper.connection.timeout.ms=18000
KRaft combined node (controller + broker, fine for dev / small prod):
process.roles=broker,controller
node.id=1
controller.quorum.voters=1@kafka1:9093,2@kafka2:9093,3@kafka3:9093
listeners=PLAINTEXT://:9092,CONTROLLER://:9093
inter.broker.listener.name=PLAINTEXT
controller.listener.names=CONTROLLER
listener.security.protocol.map=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
log.dirs=/var/lib/kafka/logs
# Note: NO zookeeper.connect setting in KRaft mode
KRaft dedicated controller node (recommended for production):
process.roles=controller
node.id=101
controller.quorum.voters=101@ctrl1:9093,102@ctrl2:9093,103@ctrl3:9093
listeners=CONTROLLER://:9093
controller.listener.names=CONTROLLER
log.dirs=/var/lib/kafka/metadata
Before the first start, format the storage directory with the cluster ID:
KAFKA_CLUSTER_ID=$(bin/kafka-storage.sh random-uuid)
bin/kafka-storage.sh format -t $KAFKA_CLUSTER_ID -c config/kraft/server.properties
The critical configuration differences: KRaft has process.roles (broker, controller, or both), node.id instead of broker.id, controller.quorum.voters listing the static voter set, and no zookeeper.connect. Forgetting to format the storage directory is the most common KRaft setup mistake — the broker refuses to start and logs No meta.properties found.
Common Mistakes & Pitfalls
Thinking the controller is involved in every produce/consume request — it only handles metadata changes (leader elections, topic creation, ISR updates), not data path
Check your understanding
Answer these without looking back at the article.
- What is the role of `controller.quorum.voters` in KRaft mode?
- Why did ZooKeeper-based Kafka cap out around 200,000 partitions?
- How does the KIP-866 ZK-to-KRaft migration work?
- What's the difference between a combined-mode and dedicated-controller KRaft node?
Related interview prep categories
2Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.