7.1 Broker Lifecycle & State Transitions
Module Overview
Goal: Understand the internal broker state machine and lifecycle phases.
What You'll Learn:
- Broker startup phases and initialization
- Registration with controller
- Partition loading and recovery
- Controlled shutdown internals
- Replica state transitions
- Broker state machine
What's NOT Covered Here:
- Controller operations (covered in Module 6.1)
- Partition internals (covered in Module 2.x)
- Replication protocol (covered in Module 3.x)
Key Insight: Brokers go through well-defined phases during startup, operation, and shutdown. Understanding broker lifecycle explains startup behavior, recovery scenarios, and graceful shutdown mechanics.
1. Broker Startup Sequence
High-Level Phases
BROKER STARTUP:
1. Configuration Loading
└─ Parse server.properties
2. Log Manager Initialization
└─ Load partitions from disk
3. Coordination Registration
└─ Register with ZooKeeper or KRaft
4. Network Layer Startup
└─ Start accepting client connections
5. Controller Notification
└─ Controller assigns leadership
6. Fully Operational
└─ Ready to serve traffic
Typical startup time:
├─ Small cluster: Seconds
├─ Large cluster (many partitions): Minutes
└─ After crash: Slower (log recovery)
Phase 1: Configuration Loading
LOAD CONFIGURATION:
1. Read server.properties:
├─ broker.id or node.id
├─ listeners (PLAINTEXT://0.0.0.0:9092)
├─ log.dirs (/var/kafka/data)
├─ zookeeper.connect or controller.quorum.voters
└─ All other configs
2. Validate configuration:
├─ Required configs present
├─ No conflicting settings
└─ Directories writable
3. Initialize logging framework (Log4j)
4. Display startup banner (version info)
Phase 2: Log Manager Initialization
LOAD PARTITIONS FROM DISK:
1. Scan log.dirs:
└─ /var/kafka/data/, /var/kafka/data2/, ...
2. For each partition directory (e.g., orders-0/):
a. Load partition metadata
b. Scan log segments:
├─ 00000000000000000000.log
├─ 00000000000001000000.log
└─ ... (all segments)
c. Validate integrity:
├─ Check CRCs
├─ Verify offset sequence
└─ Detect corruption
d. Rebuild indexes (if missing or incomplete):
├─ .index files
└─ .timeindex files
e. Recover active segment (if unclean shutdown):
└─ Truncate incomplete records
f. Load leader epoch checkpoint
g. Create in-memory Log object
3. Initialize log cleaner threads (for compaction)
4. Mark log manager as started
Time: Depends on partition count and log size
└─ Large partitions: Minutes to recover
Phase 3: Registration with Controller
ZK MODE REGISTRATION:
1. Connect to ZooKeeper ensemble
2. Create ephemeral znode:
└─ /brokers/ids/{broker_id}
└─ Data: {"version": 4, "host": "broker1", "port": 9092, ...}
3. Controller detects new broker (via watch)
4. Controller sends UpdateMetadataRequest
└─ Broker receives cluster metadata
5. Controller sends LeaderAndIsrRequest
└─ Broker learns partition assignments
KRAFT MODE REGISTRATION:
1. Generate or load broker UUID
2. Send BrokerRegistrationRequest to controller:
└─ broker_id, UUID, host, port, listeners, rack
3. Controller appends RegisterBrokerRecord to metadata log
4. Controller responds: Registration successful
5. Broker starts heartbeat loop:
└─ Periodic BrokerHeartbeatRequest to controller
6. Broker replicates metadata log (as observer)
7. Broker learns partition assignments from metadata log
Phase 4: Network Layer Startup
START ACCEPTING CONNECTIONS:
1. Create Acceptor thread:
└─ Bind to configured listeners (e.g., 0.0.0.0:9092)
2. Create Processor threads (num.network.threads):
└─ Read/write from client connections
3. Create Request Handler threads (num.io.threads):
└─ Process client requests
4. Acceptor starts accepting connections
5. Broker now reachable by clients
Note: Broker may not be fully ready:
└─ Partitions still loading or recovering
└─ Leadership not yet assigned
Phase 5: Controller Notification & Leadership Assignment
CONTROLLER ASSIGNS PARTITIONS:
1. Controller detects new broker
2. Controller checks partition assignments:
└─ Which partitions have replicas on this broker?
3. For each partition:
a. If broker should be follower:
└─ Send LeaderAndIsrRequest with follower role
b. If broker should be leader (preferred leader):
└─ Send LeaderAndIsrRequest with leader role
└─ (Or wait for preferred leader election)
4. Broker processes LeaderAndIsrRequest:
├─ For leader partitions: Start accepting writes
├─ For follower partitions: Start replicating
└─ Update local metadata
5. Broker fully operational
2. Partition Loading
Loading Replicas
FOR EACH PARTITION ON BROKER:
1. Create Replica object:
├─ Topic: orders
├─ Partition: 0
├─ Log: Reference to Log object (loaded earlier)
└─ State: NewReplica
2. Wait for controller assignment:
└─ LeaderAndIsrRequest determines role
3. Transition to operational state:
├─ OnlineReplica (follower)
└─ Or leader (if assigned)
4. Start serving:
├─ Leader: Accept produce/fetch from clients
└─ Follower: Fetch from leader
3. Controlled Shutdown
Graceful Shutdown Process
CONTROLLED SHUTDOWN:
1. Broker receives shutdown signal (SIGTERM)
2. Broker sends ControlledShutdownRequest to controller:
└─ "I'm shutting down, move my partitions"
3. Controller processes:
a. Identify partitions led by shutting-down broker
b. For each partition:
├─ Elect new leader from ISR (excluding this broker)
├─ Send LeaderAndIsrRequest to new leader
└─ New leader starts accepting writes
c. Respond to broker: "Leadership transferred"
4. Broker completes shutdown:
a. Stop accepting new client connections
b. Wait for in-flight requests to complete
c. Flush logs to disk:
└─ Ensure no data loss
d. Close network layer
e. Shutdown log manager
f. Disconnect from ZK/KRaft
g. Exit process
Result:
└─ Zero downtime (leadership transferred before shutdown)
└─ Clean state (logs flushed, no recovery needed on restart)
Controlled shutdown timeout:
└─ controlled.shutdown.max.retries (default: 3)
└─ controlled.shutdown.retry.backoff.ms (default: 5000ms)
vs Uncontrolled Shutdown (Crash)
CRASH SCENARIO:
1. Broker dies suddenly (kill -9, power loss, etc.)
2. No ControlledShutdownRequest sent
3. ZK Mode:
├─ ZK session expires (after zookeeper.session.timeout.ms)
├─ Ephemeral znode deleted
└─ Controller detects failure
KRaft Mode:
├─ Heartbeat timeout
└─ Controller marks broker offline
4. Controller reacts:
├─ Elect new leaders for affected partitions
└─ Send LeaderAndIsrRequest to new leaders
5. Brief client unavailability:
└─ Until new leaders elected and metadata propagated
6. Broker restart:
├─ Longer recovery (validate logs, rebuild indexes)
├─ Active segment may have incomplete records (truncated)
└─ Divergent data truncated (via leader epochs)
Impact:
└─ Brief downtime (seconds)
└─ Longer restart time
4. Replica State Machine
Replica States
REPLICA STATE TRANSITIONS:
NewReplica:
└─ Replica created, not yet started
OnlineFetchingReplica (Follower):
├─ Actively replicating from leader
└─ Normal operational state
OnlineReplica (Leader):
├─ Accepting client writes
└─ Serving client reads
OfflineReplica:
└─ Broker hosting replica is down
TruncatingLog:
└─ Truncating divergent log after leader change
DeletingReplica:
└─ Replica being deleted (partition reassignment or topic deletion)
NonExistentReplica:
└─ Replica fully deleted
State Transition Diagram
STATE TRANSITIONS:
NonExistentReplica → NewReplica:
└─ Partition created or reassignment adds replica
NewReplica → OnlineFetchingReplica:
└─ Broker receives LeaderAndIsrRequest (follower role)
NewReplica → OnlineReplica (Leader):
└─ Broker receives LeaderAndIsrRequest (leader role)
OnlineFetchingReplica → OnlineReplica (Leader):
└─ Elected as leader (failover)
OnlineReplica (Leader) → OnlineFetchingReplica:
└─ Demoted to follower (leader election elsewhere)
OnlineReplica/OnlineFetchingReplica → OfflineReplica:
└─ Broker failure
OfflineReplica → TruncatingLog:
└─ Broker restarts, detects divergence
TruncatingLog → OnlineFetchingReplica:
└─ Truncation complete, resume replication
OnlineReplica/OnlineFetchingReplica → DeletingReplica:
└─ Partition deletion or reassignment removal
DeletingReplica → NonExistentReplica:
└─ Replica fully deleted
5. Log Recovery
Recovery After Unclean Shutdown
ACTIVE SEGMENT RECOVERY:
1. Broker starts, detects unclean shutdown (flag file)
2. For each partition's active segment:
a. Read records sequentially
b. Validate each record batch:
├─ Check CRC
├─ Verify offset sequence
└─ Ensure completeness
c. If incomplete or corrupted record found:
├─ Truncate at last valid offset
└─ Discard partial write
d. Update LEO to last valid offset
3. Rebuild indexes:
├─ Scan valid records
├─ Regenerate .index and .timeindex
└─ Write index files to disk
4. Mark partition as recovered
5. Continue startup
Recovery time:
└─ Depends on active segment size
└─ Large segments: Minutes
6. Broker Heartbeats (KRaft Mode)
Heartbeat Protocol
KRAFT BROKER HEARTBEAT:
1. Broker sends BrokerHeartbeatRequest to controller:
└─ Every broker.heartbeat.interval.ms (default: 2 seconds)
2. Request includes:
├─ broker_id
├─ broker_epoch
├─ current_metadata_offset (log offset)
└─ want_fence (false, unless fencing self)
3. Controller responds:
├─ is_caught_up: true/false (metadata log replication)
├─ is_fenced: false (broker allowed to operate)
└─ should_shutdown: false
4. If heartbeat missed (timeout > session.timeout.ms):
└─ Controller marks broker offline
└─ Triggers partition leader elections
5. Broker continues heartbeat loop until shutdown
Purpose:
└─ Prove liveness to controller
└─ Sync metadata log replication status
7. Broker Startup Observability
Monitoring Broker Startup
WHY MONITOR STARTUP:
Diagnose:
├─ Startup failures
├─ Slow recovery
├─ Configuration issues
└─ Partition loading problems
Track:
├─ Startup duration
├─ Partition loading progress
├─ Controller election
└─ Readiness status
Key Log Messages During Startup
PHASE 1: CONFIGURATION LOADING
Log messages:
INFO [KafkaServer] Starting Kafka version 3.x.x
INFO [KafkaServer] Kafka server started with broker ID 1
INFO [KafkaServer] Registered broker 1 in cluster with ZK/KRaft
What it indicates:
├─ Broker process started successfully
├─ Configuration loaded and validated
└─ Broker ID assigned/confirmed
Look for errors:
ERROR [KafkaServer] Fatal error during broker startup
└─ Configuration invalid, exiting
PHASE 2: LOG MANAGER INITIALIZATION
Log messages:
INFO [LogManager] Loading logs from /var/lib/kafka/data
INFO [Log partition=orders-0, dir=/var/lib/kafka/data] Completed load of log with 3 segments, size 1024 MB
INFO [Log partition=users-1, dir=/var/lib/kafka/data] Recovering segment offsets 0-1000000
INFO [LogManager] Loaded 1234 logs in 3456 ms
INFO [LogManager] Logs loaded successfully
What it indicates:
├─ Partition logs discovered
├─ Segments validated and loaded
├─ Recovery completed (if needed)
└─ Time taken for log loading
Performance indicator:
└─ Large partition count or corrupted logs → slow startup
PHASE 3: CLUSTER REGISTRATION
ZK Mode:
INFO [KafkaServer] Connecting to ZooKeeper at zk1:2181,zk2:2181,zk3:2181
INFO [KafkaServer] Successfully connected to ZooKeeper
INFO [KafkaServer] Registered broker 1 in ZooKeeper
KRaft Mode:
INFO [KafkaServer] Registered broker 1 with controller quorum
INFO [BrokerServer] Completed registration with controller
INFO [MetadataLoader] Loaded metadata log up to offset 5678
What it indicates:
├─ Broker joined cluster successfully
├─ Metadata synchronization started
└─ Ready to receive partition assignments
PHASE 4: CONTROLLER STATUS
Controller election (if applicable):
INFO [Controller] Controller moved to broker 1
INFO [Controller] Elected as the controller with epoch 5
INFO [ControllerEventThread] Starting controller event processor thread
Non-controller broker:
INFO [MetadataCache] Updated metadata for cluster
INFO [Replica Manager] Started replication for partitions [orders-0, users-1, ...]
What it indicates:
├─ Broker knows its role (controller or data broker)
├─ Partition assignments received
└─ Ready for traffic
PHASE 5: READY FOR TRAFFIC
Final startup messages:
INFO [KafkaServer] Kafka broker 1 is ready to serve requests
INFO [SocketServer] Accepting connections on listener PLAINTEXT://0.0.0.0:9092
INFO [Kafka Server] started (kafka.server.KafkaServer)
What it indicates:
├─ All phases complete
├─ Network layer accepting connections
└─ Broker fully operational
Internal Topics to Monitor
KAFKA INTERNAL TOPICS:
1. __cluster_metadata (KRaft mode):
```bash
kafka-topics.sh --bootstrap-server localhost:9092 --list | grep metadata
# Output: __cluster_metadata
kafka-topics.sh --bootstrap-server localhost:9092 \
--describe --topic __cluster_metadata
# Should show: 1 partition, RF=3 (or quorum size)
Purpose: └─ Stores cluster metadata in KRaft mode └─ Presence indicates KRaft operational
- __consumer_offsets:
kafka-topics.sh --bootstrap-server localhost:9092 --list | grep offsets
# Output: __consumer_offsets
kafka-topics.sh --bootstrap-server localhost:9092 \
--describe --topic __consumer_offsets
# Should show: 50 partitions (default), RF=3
Purpose: └─ Stores consumer group offsets └─ Created automatically on first consumer group
- __transaction_state:
kafka-topics.sh --bootstrap-server localhost:9092 --list | grep transaction
# Output: __transaction_state
# Should show: 50 partitions (default), RF=3
Purpose: └─ Stores transactional producer state └─ Created automatically on first transaction
---
### JMX Metrics for Startup
BROKER STATE METRIC:
kafka.server:type=KafkaServer,name=BrokerState
Values: ├─ 0: Not Running ├─ 1: Starting ├─ 2: RecoveringFromUncleanShutdown ├─ 3: RunningAsBroker ├─ 4: RunningAsController ├─ 5: PendingControlledShutdown └─ 6: BrokerShuttingDown
Monitor during startup:
# Using jmxterm
echo "get -b kafka.server:type=KafkaServer,name=BrokerState Value" | \
java -jar jmxterm.jar -l localhost:9999 -n
# Should transition: 0 → 1 → 3 (or 4 if controller)
Expected transition time: ├─ Small cluster: 0→3 in 5-10 seconds ├─ Large cluster: 0→3 in 30-60 seconds └─ Recovery: 2→3 may take minutes (validate logs)
---
LOG LOADING METRICS:
kafka.log:type=LogManager,name=LogLoadTime └─ Time taken to load all partition logs
kafka.log:type=LogManager,name=NumPartitions └─ Total partitions loaded on this broker
Monitor:
echo "get -b kafka.log:type=LogManager,name=LogLoadTime Value" | \
java -jar jmxterm.jar -l localhost:9999 -n
Alert if: └─ LogLoadTime > 5 minutes (investigate slow recovery)
---
REPLICATION METRICS:
kafka.server:type=ReplicaManager,name=LeaderCount └─ Number of partitions this broker leads
kafka.server:type=ReplicaManager,name=PartitionCount └─ Total partitions (leader + follower) on this broker
Monitor after startup:
# Should match expected partition assignments
echo "get -b kafka.server:type=ReplicaManager,name=PartitionCount Value" | \
java -jar jmxterm.jar -l localhost:9999 -n
---
## 8. Common Broker Startup Pitfalls
### Troubleshooting Table
COMMON ISSUES AND SOLUTIONS:
| Issue | Cause | Solution |
|-------|-------|----------|
| **Stuck on log recovery** | Corrupted segment or disk issue | Check disk health with `smartctl`, delete corrupt segment, restore from replica |
| **Broker not joining cluster** | Misconfigured `broker.id` or `node.id`, network issues | Verify ID uniqueness: `grep broker.id config/*.properties`, check network: `telnet broker1 9092` |
| **Controller flapping** | ZooKeeper instability or high load | Increase ZK session timeout: `zookeeper.session.timeout.ms=18000`, check ZK health |
| **Long startup time** | Too many partitions on broker | Reduce partitions per broker, increase `num.recovery.threads.per.data.dir=4` |
| **Out of memory** | Large partition count, insufficient heap | Increase JVM heap: `KAFKA_HEAP_OPTS="-Xmx4g -Xms4g"`, reduce partition count |
| **Port already in use** | Previous broker process still running | Kill old process: `kill -9 $(lsof -t -i:9092)` or `pkill -9 kafka` |
| **Cannot connect to ZK/KRaft** | Network issue, ZK/controller down | Verify ZK/controller health, check firewall rules, test connectivity |
| **Metadata not syncing** | Controller not reachable | Check controller logs, verify controller election, test network to controller |
---
### Detailed Troubleshooting Steps
ISSUE: Stuck on Log Recovery
Symptoms: ├─ Broker startup hangs ├─ Log shows: "Recovering segment offsets..." └─ No progress for >5 minutes
Diagnosis:
# Check disk health
sudo smartctl -a /dev/sda
# Check for corrupted segments
grep ERROR /var/log/kafka/server.log | grep -i corrupt
# Check disk I/O
iostat -x 1 10
Solution:
# If specific segment corrupted, delete it
rm /var/lib/kafka/data/orders-0/00000000000012345678.log
# Broker will recover from replica
# If disk failing, replace disk and restore from replica
---
ISSUE: Broker Not Joining Cluster
Symptoms:
├─ Broker starts but not listed in metadata
├─ Producers/consumers cannot connect
└─ kafka-broker-api-versions.sh fails
Diagnosis:
# Verify broker.id uniqueness
grep broker.id /etc/kafka/server.properties
kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic __cluster_metadata
# Check network connectivity
telnet broker1.example.com 9092
# Check firewall
sudo iptables -L -n | grep 9092
Solution:
# Fix broker.id if duplicate
broker.id=4 # Ensure unique
# Fix network/firewall
sudo iptables -A INPUT -p tcp --dport 9092 -j ACCEPT
# Restart broker
kafka-server-stop.sh && kafka-server-start.sh config/server.properties
---
ISSUE: Controller Flapping
Symptoms: ├─ Controller election every few seconds ├─ Logs show: "Elected as controller" repeatedly └─ Cluster unstable
Diagnosis:
# Count controller elections
grep -c "Successfully elected as the controller" /var/log/kafka/server.log
# If > 10 in last hour, flapping
# Check ZK health (if ZK mode)
echo stat | nc zookeeper1 2181
# Check network latency
ping -c 10 controller1.example.com
Solution:
# Increase ZK session timeout
zookeeper.session.timeout.ms=18000 # 18 seconds (from default 6s)
# Check ZK capacity
# Increase ZK heap if needed: -Xmx2g
# Reduce broker load
# Scale cluster if overwhelmed
---
ISSUE: Long Startup Time
Symptoms: ├─ Broker takes >10 minutes to start ├─ Log shows slow partition loading └─ "Loaded 5000 logs in 600000 ms"
Diagnosis:
# Check partition count
kafka-topics.sh --bootstrap-server localhost:9092 --describe | wc -l
# Check disk I/O
iostat -x 1 10
# Look for high %util
# Check recovery threads
grep num.recovery.threads.per.data.dir config/server.properties
Solution:
# Increase recovery threads
num.recovery.threads.per.data.dir=4 # Default: 1
# Use faster disks (SSDs)
# Or spread partitions across more brokers
# Reduce partition count per broker
# via partition reassignment
---
### Monitoring Startup Progress
```bash
# Watch broker state in real-time
watch -n 1 'echo "get -b kafka.server:type=KafkaServer,name=BrokerState Value" | java -jar jmxterm.jar -l localhost:9999 -n'
# Monitor log loading
tail -f /var/log/kafka/server.log | grep "Loading logs"
# Check partition count
watch -n 1 'kafka-topics.sh --bootstrap-server localhost:9092 --describe | grep "Leader: 1" | wc -l'
# Verify broker registered
kafka-broker-api-versions.sh --bootstrap-server localhost:9092 | grep "broker 1"
9. Key Takeaways
You've learned:
✅ Broker startup — config load, log recovery, registration, network start
✅ Log manager initialization — scan partitions, validate, rebuild indexes
✅ Registration: ZK (ephemeral znode) vs KRaft (BrokerRegistrationRequest)
✅ Controlled shutdown — proactive leadership transfer, zero downtime
✅ Uncontrolled shutdown (crash) — controller detects timeout, elects new leaders
✅ Replica states — New → Online → Offline → Truncating → Deleting
✅ Log recovery — truncate incomplete records, rebuild indexes
✅ KRaft heartbeats — prove liveness, sync metadata log
✅ Startup time — depends on partition count and log size
✅ Graceful shutdown — flush logs, transfer leadership, clean exit
Summary
Broker lifecycle is well-structured and fault-tolerant:
Startup Phases =
├─ 1. Load configuration
├─ 2. Initialize log manager (load partitions)
├─ 3. Register with controller (ZK or KRaft)
├─ 4. Start network layer
├─ 5. Receive partition assignments
└─ 6. Fully operational
Shutdown Types =
├─ Controlled: ControlledShutdownRequest, leadership transfer, clean exit
└─ Uncontrolled (crash): Timeout detection, controller reacts
Replica States =
├─ New → Online (Leader/Follower)
├─ Online → Offline (failure)
├─ Offline → Truncating → Online (recovery)
└─ Online → Deleting → NonExistent (deletion)
Recovery =
├─ Validate active segment
├─ Truncate incomplete records
├─ Rebuild indexes
└─ Resume operation
Liveness =
├─ ZK: Ephemeral znode (session timeout)
└─ KRaft: Heartbeat loop (BrokerHeartbeatRequest)
Remember: Understanding broker lifecycle explains startup times, recovery behavior, and shutdown mechanics. Controlled shutdown is always preferable to crashes (faster recovery, no data loss).
Next up: Module 8.1 — Transaction & Exactly-Once Internals (Broker Side) — The final module!