5.2 ZooKeeper Coordination (Legacy)
Module Overview
Goal: Understand ZooKeeper's role in Kafka coordination (legacy, pre-KRaft).
What You'll Learn:
- ZooKeeper responsibilities in Kafka
- Znode layout and structure
- Controller election (ZK-based)
- Metadata storage in ZK
- Watches and notifications
- ZooKeeper limitations
What's NOT Covered Here:
- KRaft coordination (covered in Module 5.3)
- Controller internals (covered in Module 6.1)
- General ZooKeeper administration (out of scope)
Key Insight: ZooKeeper was Kafka's original coordination layer, providing consensus, metadata storage, and failure detection. Understanding ZK's role explains legacy Kafka behavior and motivates the move to KRaft.
Note: ZooKeeper mode is being deprecated. Kafka 3.3+ supports KRaft as the recommended coordination system.
1. ZooKeeper's Role in Kafka
Core Responsibilities
ZOOKEEPER PROVIDES:
1. Controller Election:
└─ Leader election among brokers to determine controller
2. Broker Registration:
└─ Ephemeral znodes track live brokers
3. Metadata Storage:
└─ Topic configs, partition assignments, ISR state
4. Configuration Management:
└─ Broker and topic configuration overrides
5. Failure Detection:
└─ Session timeouts for broker liveness
6. Distributed Coordination:
└─ Watches notify brokers of changes
2. Znode Layout
ZooKeeper Path Structure
KAFKA'S ZNODE HIERARCHY:
/
├─ admin/
│ ├─ delete_topics/
│ │ └─ {topic} # Topics pending deletion
│ └─ reassign_partitions # Partition reassignment state
│
├─ brokers/
│ ├─ ids/
│ │ ├─ 0 # Ephemeral node for Broker 0
│ │ ├─ 1 # Ephemeral node for Broker 1
│ │ └─ ...
│ ├─ topics/
│ │ └─ {topic}/
│ │ └─ partitions/
│ │ └─ {partition}/
│ │ └─ state # Partition leader, ISR
│ └─ seqid # Broker ID sequence generator
│
├─ config/
│ ├─ topics/
│ │ └─ {topic} # Topic-level config overrides
│ ├─ brokers/
│ │ └─ {broker_id} # Broker-level config overrides
│ └─ changes/ # Config change notifications
│
├─ controller # Current controller broker ID
│
├─ controller_epoch # Controller epoch (version)
│
├─ isr_change_notification/ # ISR change events
│
└─ log_dir_event_notification/ # Log directory failure events
3. Broker Registration
Ephemeral Znode for Liveness
BROKER STARTUP:
1. Broker connects to ZooKeeper
└─ Establishes session
2. Broker creates ephemeral znode:
└─ Path: /brokers/ids/{broker_id}
└─ Data: {
"version": 4,
"host": "broker1.example.com",
"port": 9092,
"endpoints": ["PLAINTEXT://broker1:9092"],
"rack": "us-east-1a",
"timestamp": "1609459200000"
}
3. Controller watches /brokers/ids/
└─ Notified when brokers join/leave
4. If broker crashes:
└─ ZK session expires
└─ Ephemeral znode deleted automatically
└─ Controller detects broker failure
4. Controller Election
Leader Election Using ZK
CONTROLLER ELECTION PROCESS:
1. All brokers watch /controller znode
2. Current controller:
└─ Holds ephemeral znode at /controller
└─ Data: {"brokerid": 0, "timestamp": "..."}
3. If controller crashes:
├─ ZK session expires
├─ /controller znode deleted
└─ All brokers notified (via watch)
4. Brokers race to create /controller znode:
├─ First broker to successfully create becomes controller
├─ Others fail (znode already exists)
└─ Failed brokers continue watching
5. New controller:
├─ Increments controller epoch
├─ Loads cluster state from ZK
└─ Starts managing partitions
Controller Epoch
CONTROLLER VERSIONING:
/controller_epoch znode:
└─ Contains integer epoch value
Incremented on each controller election:
├─ Controller 0 (epoch 1)
├─ Controller 1 (epoch 2)
└─ Controller 0 again (epoch 3)
Purpose:
├─ Prevents stale controllers from making decisions
└─ Brokers reject requests from old controller epochs
5. Topic and Partition Metadata
Topic Configuration
TOPIC METADATA IN ZK:
/brokers/topics/{topic}:
└─ Data: {
"version": 1,
"partitions": {
"0": [1, 2, 3], # Partition 0, replicas on brokers 1,2,3
"1": [2, 3, 1],
"2": [3, 1, 2]
}
}
/config/topics/{topic}:
└─ Data: {
"version": 1,
"config": {
"retention.ms": "604800000",
"cleanup.policy": "delete",
"min.insync.replicas": "2"
}
}
Partition State
PARTITION STATE IN ZK:
/brokers/topics/{topic}/partitions/{partition}/state:
└─ Data: {
"version": 1,
"leader": 1,
"leader_epoch": 5,
"controller_epoch": 2,
"isr": [1, 2],
"version": 1
}
Updated by controller:
├─ On leader election
├─ On ISR changes
└─ Brokers read this for leadership info
6. Watches and Notifications
ZooKeeper Watches
KAFKA USES WATCHES FOR CHANGE DETECTION:
Controller watches:
├─ /brokers/ids/ → Broker join/leave
├─ /brokers/topics/{topic} → Topic changes
├─ /admin/delete_topics/ → Topic deletion requests
└─ /admin/reassign_partitions → Reassignment requests
Brokers watch:
├─ /controller → Controller changes
└─ Topic/partition state changes (via controller notifications)
When znode changes:
├─ ZK sends one-time notification
├─ Watcher must re-register watch
└─ Kafka processes change and re-watches
ISR Change Notifications
ISR CHANGES:
When leader updates ISR:
1. Leader writes new ISR to /brokers/topics/{topic}/partitions/{partition}/state
2. Leader creates child znode in /isr_change_notification/
3. Controller watches /isr_change_notification/
4. Controller notified of ISR change
5. Controller processes change
6. Controller deletes notification znode (acknowledgment)
Benefit:
└─ Controller learns of ISR changes immediately
└─ Updates cluster metadata accordingly
7. ZooKeeper Limitations
Scalability Issues
ZK LIMITATIONS IN LARGE KAFKA CLUSTERS:
1. Write Throughput:
└─ ZK is designed for low-volume metadata
└─ Frequent ISR changes → high ZK write load
└─ Becomes bottleneck in large clusters
2. Partition Scale:
└─ Millions of partitions → millions of znodes
└─ ZK metadata size grows large
└─ Slower controller failover (must load all znodes)
3. Controller Bottleneck:
└─ Single controller reads/writes ZK
└─ ZK latency impacts controller throughput
4. Operational Complexity:
└─ Separate ZK cluster to manage
└─ Different failure modes
└─ Additional operational overhead
Session Management Complexity
ZK SESSION ISSUES:
Long GC pauses:
├─ Broker JVM pauses
├─ ZK heartbeats missed
├─ Session expires (false positive)
└─ Broker considered dead (even though alive)
Split-brain risk:
├─ Broker loses ZK connectivity
├─ Controller thinks broker dead
├─ Broker thinks it's still alive
└─ Must fence operations
Session timeout trade-off:
├─ Low timeout: Fast failure detection, false positives
└─ High timeout: Slower failure detection, fewer false positives
8. ZooKeeper vs KRaft
Why Move to KRaft?
KRAFT ADVANTAGES:
1. No External Dependency:
└─ Kafka manages its own metadata (self-sufficient)
2. Better Scalability:
└─ Metadata log designed for high partition count
└─ Faster controller failover
3. Simplified Operations:
└─ No separate ZK cluster to manage
└─ One system to operate and monitor
4. Improved Performance:
└─ Lower latency for metadata updates
└─ Higher throughput for partition operations
5. Modern Design:
└─ Raft-based consensus (proven algorithm)
└─ Built for Kafka's workload
Deprecation timeline:
├─ Kafka 2.8: KRaft preview
├─ Kafka 3.3: KRaft production-ready
├─ Kafka 4.0: ZK mode removal (planned)
└─ New deployments should use KRaft
9. Key Takeaways
You've learned:
✅ ZooKeeper provides controller election, broker registration, metadata storage
✅ Ephemeral znodes track broker liveness (deleted on session expiry)
✅ Controller election via race to create /controller znode
✅ Znode layout organizes brokers, topics, configs, partitions
✅ Watches notify controller and brokers of changes
✅ ISR changes propagated via /isr_change_notification/
✅ ZK limitations — scalability, latency, operational complexity
✅ KRaft replaces ZK — self-managed metadata, better performance
✅ Deprecation timeline — ZK mode being phased out
✅ New deployments should use KRaft
Summary
ZooKeeper was Kafka's original coordination layer:
ZooKeeper Role =
├─ Controller election (leader election)
├─ Broker registration (ephemeral znodes)
├─ Metadata storage (topics, partitions, ISR)
├─ Failure detection (session timeouts)
└─ Change notifications (watches)
Znode Structure =
├─ /brokers/ids/{id} → Broker registration
├─ /brokers/topics/{topic} → Partition assignments
├─ /controller → Current controller
├─ /controller_epoch → Controller version
└─ /config/topics/{topic} → Topic configs
Limitations =
├─ Scalability bottleneck (large clusters)
├─ Operational complexity (separate system)
├─ Session management issues (false positives)
└─ Motivates KRaft migration
Migration =
├─ KRaft is the future (self-managed metadata)
├─ ZK mode deprecated (Kafka 4.0 removal planned)
└─ New deployments should use KRaft
Remember: ZooKeeper served Kafka well for many years but has scalability and operational limitations. KRaft (next module) is Kafka's modern, self-managed coordination system.
Next up: Module 5.3 — KRaft Metadata Quorum — Modern Kafka coordination.