Kafka Architecture Deep Dive
Log Segments and Retention Policies
How files are segmented on disk and cleaned up via time/size thresholds.
Introduction
In Kafka, a partition is physically represented as a directory on the broker's local filesystem. Senders write events to this directory. However, Kafka does not write to a single file. Instead, the partition is split into Log Segments.
Why It Matters
Writing to a single file degrades performance. Searching for messages by offset requires scanning the entire file, and deleting old data blocks is extremely slow. Segmenting the log files into smaller blocks allows Kafka to quickly roll old segments, clean up data, and keep disk seeks low.
Real-World Analogy
Think of partition logs like a daily newspaper archivist. Instead of pasting every day's news onto one giant scroll of paper, the archivist binds them into daily folders (segments). When a folder is 7 days old, they can shred it (retention) easily without touching the other papers.
How It Works
The lifecycle of segment management flows as follows:
- Active Segment: The current segment where writes occur. Only one active segment exists per partition.
- Closed Segments: Read-only segments. Once a segment reaches size (default 1GB) or time limits (default 7 days), it rolls and closes.
- Index Files: Every segment has
.log(raw events),.index(offset to physical byte map), and.timeindexfiles.
Internal Architecture
Kafka supports two data retention policies:
- Log Deletion: Discards inactive segments once they exceed age thresholds (
log.retention.hours) or size limits (log.retention.bytes). - Log Compaction: Retains only the latest value for each message key, discarding historical updates. This is useful for state cache storage.
Visual Explanation
Below is an ASCII representation of the partition segment directories on disk:
/var/lib/kafka/data/orders-topic-0/
├── 00000000000000000000.log (Closed segment, offsets 0-999)
├── 00000000000000000000.index
├── 00000000000000001000.log (Active segment, offsets 1000+)
└── 00000000000000001000.index
Practical Example
Below are CLI configurations demonstrating how to set segment size and time limits on a topic dynamically:
# Set log retention to 72 hours (3 days)
kafka-configs.sh --bootstrap-server localhost:9092 --alter --entity-type topics --entity-name orders-topic --add-config retention.ms=259200000
# Set log segment roll size to 256MB
kafka-configs.sh --bootstrap-server localhost:9092 --alter --entity-type topics --entity-name orders-topic --add-config segment.bytes=268435456
Common Mistakes
- Setting Retention Bytes lower than maximum batch sizes: Causes segments to delete as soon as they roll, resulting in message loss.
- Enabling compaction on null-key topics: Log compaction requires key-value pairings. Null keys cause the compaction thread to throw errors and stall.
Quick Quiz
Q1: Does Kafka clean up or compress the active log segment?
No. Only closed, inactive segments are eligible for deletion or compaction. The active segment is left open for write appending.
Q2: How does Kafka find a message at offset 1005?
By performing a binary search on the segment index file (e.g. 1000.index) to locate the closest byte position, and scanning sequentially from there.
Scenario-Based Challenge
The Challenge: Sizing Retention for Disaster Recovery
You run a microservices log stream. Downstream analytics engines take 2 days to recover from database corruption and replay logs. The log volume is 2TB per day. How do you configure the topic's retention parameters?
Solution Tip: Set retention.ms to at least 3 days (259200000ms) to ensure the 2-day recovery window is fully covered. Additionally, verify that retention.bytes is set to at least 6TB (or disabled) to prevent disk space limits from triggering earlier deletions.
Debugging Exercise
A Kafka broker disk partition is 100% full, but the log cleanups are configured with a 3-day retention time limit. Senders cannot write.
The Fix: Check the size of the active segment. If segment.bytes=1073741824 (1GB) and traffic is very slow, the active segment has not reached 1GB and will not roll, preventing cleanups. To fix this:
- Reduce
segment.bytes. - Or configure a time-based roll setting:
segment.ms=86400000(24 hours).
Interview Questions
1. Explain what happens during log compaction.
A cleaner thread reads the dirty ratio of closed segments, merges duplicate keys, and writes compact segments, keeping only the latest value for each key.
2. What are .timeindex files used for?
To search for messages by timestamp. It maps a Unix timestamp to an offset number, letting consumers seek to a specific date/time.
Production Considerations
Configure XFS filesystem mount options (e.g. noatime) to prevent the OS from writing updates to files during read polls, improving IO performance.