Apache Kafka
Overview
Apache Kafka is a distributed streaming platform originally developed at LinkedIn in 2010. It functions as a distributed commit log, providing durable, high-throughput, fault-tolerant messaging. Kafka is used for real-time data pipelines, event sourcing, log aggregation, and stream processing. It’s the backbone of many modern data architectures.
Architecture
graph TD
subgraph "Kafka Cluster"
B1[Broker 1] --> Z[ZooKeeper/KRaft]
B2[Broker 2] --> Z
B3[Broker 3] --> Z
end
P[Producers] --> B1
P --> B2
P --> B3
B1 --> C[Consumers]
B2 --> C
B3 --> C
Core Concepts
Topics and Partitions
graph TD
subgraph "Topic: user-events"
subgraph "Partition 0"
M0_0["Msg 0 (offset 0)"]
M0_1["Msg 1 (offset 1)"]
M0_2["Msg 2 (offset 2)"]
end
subgraph "Partition 1"
M1_0["Msg 0 (offset 0)"]
M1_1["Msg 1 (offset 1)"]
end
subgraph "Partition 2"
M2_0["Msg 0 (offset 0)"]
M2_1["Msg 1 (offset 1)"]
M2_2["Msg 2 (offset 2)"]
M2_3["Msg 3 (offset 3)"]
end
end
| Concept | Description |
|---|---|
| Topic | Named stream of records (like a table) |
| Partition | Ordered, immutable sequence of records |
| Offset | Unique ID for each record within a partition |
| Broker | Server that stores partitions |
| Replica | Copy of a partition for fault tolerance |
| Leader | Replica that handles reads/writes |
| Follower | Replica that replicates from leader |
Partition Assignment
# Key-based partitioning (same key → same partition)
partition = hash(key) % num_partitions
# No key → round-robin
partition = next_partition_round_robin()
graph LR
K1["Key: user_123"] --> P0["hash('user_123') % 3 = 0"]
K2["Key: user_456"] --> P1["hash('user_456') % 3 = 1"]
K3["Key: user_789"] --> P2["hash('user_789') % 3 = 2"]
K1 --> P0
K2 --> P1
K3 --> P2
Replication
graph TD
subgraph "Topic Partition 0 (replication-factor=3)"
L[Leader (Broker 1)] --> F1[Follower (Broker 2)]
L --> F2[Follower (Broker 3)]
end
P[Producer] -->|Write| L
C[Consumer] -->|Read| L
In-Sync Replicas (ISR)
graph TD
subgraph "ISR = {Broker 1, Broker 2, Broker 3}"
B1[Broker 1 (Leader)] --> B2[Broker 2]
B1 --> B3[Broker 3]
end
B2 -.->|Falls behind| B4[Out of ISR]
B2 -->|"Catches up"| B2
| Config | Description |
|---|---|
replication.factor=3 | 3 copies of each partition |
min.insync.replicas=2 | At least 2 replicas must ACK |
acks=all | Producer waits for all ISR to ACK |
Producers
graph LR
P[Producer] --> B[Batching]
B --> S[Serialization]
S --> PA[Partitioner]
PA --> Broker[Broker]
Broker -->|ACK| P
Producer Configuration
producer = KafkaProducer(
bootstrap_servers=['broker1:9092', 'broker2:9092'],
# Durability
acks='all', # Wait for all ISR
retries=3, # Retry on failure
enable_idempotence=True, # Exactly-once producer
# Performance
batch_size=16384, # Batch size in bytes
linger_ms=10, # Wait time for batching
compression_type='lz4', # Compression
# Ordering
max_in_flight_requests_per_connection=5 # With idempotence, order preserved
)
Delivery Guarantees
graph TD
subgraph "acks=0"
A0[Fire and forget]
A0 --> L0[May lose messages]
end
subgraph "acks=1"
A1[Leader ACK only]
A1 --> L1[May lose if leader fails]
end
subgraph "acks=all"
A2[All ISR ACK]
A2 --> S2[Safest]
end
Consumer Groups
graph TD
subgraph "Consumer Group: analytics"
C1[Consumer 1] --> P0[Partition 0]
C2[Consumer 2] --> P1[Partition 1]
C3[Consumer 3] --> P2[Partition 2]
end
subgraph "Consumer Group: monitoring"
C4[Consumer 4] --> P0
C5[Consumer 5] --> P1
C6[Consumer 6] --> P2
end
Consumer Group Rules
- Each partition is consumed by exactly one consumer in a group
- A consumer can consume multiple partitions
- If consumers > partitions, some consumers are idle
- Multiple groups can consume the same topic independently
Consumer Rebalancing
sequenceDiagram
participant C1 as Consumer 1
participant C2 as Consumer 2
participant C3 as Consumer 3 (joins)
participant B as Broker
Note over C1,C2: Initial: C1→P0, C2→P1
C3->>B: Join group
B->>B: Rebalance
B->>C1: Assign P0
B->>C2: Assign P1
B->>C3: Assign P2
Note over C1,C3: After: C1→P0, C2→P1, C3→P2
Offset Management
graph TD
subgraph "Partition 0"
O0[offset 0]
O1[offset 1]
O2[offset 2]
O3[offset 3]
O4[offset 4]
end
C[Consumer] -->|"committed offset = 2"| O2
Note["Consumer will read from offset 3 next"]
Offset Commit Strategies
| Strategy | Description | Trade-off |
|---|---|---|
| Auto-commit | Commit periodically | May lose/duplicate |
| Manual commit | Commit after processing | At-least-once |
| Transactional | Commit with processing | Exactly-once |
Exactly-Once Semantics
sequenceDiagram
participant P as Producer
participant B as Broker
participant C as Consumer
Note over P,C: Idempotent Producer
P->>B: Send (producer_id=PID, seq=0)
B->>B: Dedup check
B-->>P: ACK
P->>B: Send (producer_id=PID, seq=1)
B->>B: Dedup check
B-->>P: ACK
Note over P,C: Transactional Consumer
C->>B: Read offset 0-2
C->>C: Process
C->>B: Commit transaction (offset 3 + output)
B->>B: Atomic commit
Log Compaction
graph TD
subgraph "Before Compaction"
K1["Key A: value 1 (offset 0)"]
K2["Key B: value 1 (offset 1)"]
K3["Key A: value 2 (offset 2)"]
K4["Key B: value 2 (offset 3)"]
K5["Key A: value 3 (offset 4)"]
end
subgraph "After Compaction"
K3c["Key A: value 3 (offset 4)"]
K4c["Key B: value 2 (offset 3)"]
end
Log compaction retains only the latest value for each key, useful for changelogs and event sourcing.
Kafka vs. Traditional Message Queues
| Aspect | Kafka | RabbitMQ/ActiveMQ |
|---|---|---|
| Model | Distributed log | Message broker |
| Retention | Time/key-based | Until consumed |
| Replay | Yes (from offset) | No |
| Ordering | Per-partition | Per-queue |
| Throughput | Very high (millions/sec) | Moderate |
| Use case | Event streaming, data pipelines | Task queues, RPC |
Interview Questions
-
What is Kafka and how does it differ from traditional message queues?
- Kafka is a distributed commit log. Unlike traditional queues, messages are retained (not deleted after consumption), consumers can replay messages, and it provides per-partition ordering with very high throughput.
-
Explain Kafka topics, partitions, and offsets.
- Topic: named stream of records. Partition: ordered, immutable sequence within a topic. Offset: unique position of each record within a partition. Partitions enable parallelism and ordering per key.
-
What is a consumer group?
- A group of consumers that cooperatively consume a topic. Each partition is assigned to exactly one consumer in the group. Multiple groups can independently consume the same topic.
-
How does Kafka achieve durability?
- Messages are persisted to disk and replicated across brokers. The replication factor determines how many copies exist. ISR (in-sync replicas) must acknowledge writes for durability.
-
What is the ISR in Kafka?
- In-Sync Replicas: the set of replicas that are fully caught up with the leader.
min.insync.replicasconfigures how many must be in sync. If a replica falls behind, it’s removed from ISR.
- In-Sync Replicas: the set of replicas that are fully caught up with the leader.
-
How does Kafka handle consumer rebalancing?
- When consumers join/leave a group, the broker triggers a rebalance. Partitions are redistributed among consumers. During rebalance, consumption pauses briefly.
Common Mistakes
- Setting
acks=1when durability matters — leader failure can lose messages - Not configuring
min.insync.replicas— single broker failure can lose data - Too few partitions — limits consumer parallelism
- Not handling consumer rebalancing — can cause duplicate processing
- Ignoring consumer lag — consumers fall behind producers
- Using Kafka as a task queue — it’s designed for streaming, not work distribution
Summary
Kafka is a distributed streaming platform that provides durable, high-throughput, fault-tolerant messaging. Topics are divided into partitions for parallelism, and consumer groups enable scalable consumption. Key design choices include replication factor, ISR configuration, and acknowledgment settings. Kafka excels at event streaming, log aggregation, and data pipelines.
Cross-References
- Messaging Overview — Messaging concepts
- Message Queues — General queue patterns
- RabbitMQ — Traditional message broker
- Pub/Sub — Publish-subscribe patterns
- Stream Processing — Kafka Streams
- Consistent Hashing — Partition assignment