---
title: Kafka Architecture
url: https://doc.liz6.com/en/distributed-systems/07-messages-and-streams/02-kafka-architecture
locale: en
area: distributed-systems
tags:
- distributed-systems
- messages-and-streams
date: 2026-06-30
modified: 2026-07-16
description: Kafka models the messaging system as an immutable, partitioned, replayable log—not a "consume-and-delete" queue. In-partition ordering guarantees message order for the same key, the ISR mechanism controls the trade-off between replication and durability, and consumer groups turn partition ownership negotiation into a distributed coordination problem.
---

# Kafka Architecture

> Kafka models the messaging system as an immutable, partitioned, replayable log—not a "consume-and-delete" queue. In-partition ordering guarantees message order for the same key, the ISR mechanism controls the trade-off between replication and durability, and consumer groups turn partition ownership negotiation into a distributed coordination problem.

## Partition: Ordered Immutable Log

```
Topic = multiple partitions:
  Partition 0: [offset 0][offset 1][offset 2]...[offset N]  ← append only
  Partition 1: [offset 0][offset 1][offset 2]...[offset N]
  Partition 2: [offset 0][offset 1][offset 2]...[offset N]

Producer: choose partition by key: partition = murmur2(key) % N_partitions
  → same key goes to the same partition → messages for that key are ordered
  → key=null → round-robin (load balancing, unordered)

Consumer: pull-based, offset managed by the consumer
```

## ISR (In-Sync Replica)

Each partition has 1 leader replica + N follower replicas. Only replicas in the ISR are considered "in-sync":

```
Leader: producer writes → leader: append to log → followers: fetch from leader
  → follower acknowledges: I've replicated up to offset X
  → if follower doesn't acknowledge within replica.lag.time.max.ms → removed from ISR
  → min.insync.replicas: each message needs this many ISR replicas to acknowledge to be considered committed
```

If the leader crashes, a new leader is elected from the followers in the ISR. Followers not in the ISR risk having their logs truncated (log diverged from leader).

## Consumer Group

A partition of a topic can only be consumed by **one** consumer within the same consumer group. Partitions are distributed among group members.

<svg viewBox="0 0 720 320" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="Consumer Group partition assignment and rebalance after crash">
  <defs><marker id="kfarr" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker></defs>
  <rect width="720" height="320" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">Consumer Group: A partition can only be consumed by 1 consumer in the group</text>
  <rect x="190" y="46" width="340" height="34" rx="8" fill="#4f46e5"/>
  <text x="360" y="68" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">Topic: 3 partitions</text>
  <line x1="250" y1="80" x2="120" y2="122" stroke="#475569" stroke-width="1.6" marker-end="url(#kfarr)"/>
  <line x1="360" y1="80" x2="360" y2="122" stroke="#475569" stroke-width="1.6" marker-end="url(#kfarr)"/>
  <line x1="470" y1="80" x2="600" y2="122" stroke="#475569" stroke-width="1.6" marker-end="url(#kfarr)"/>
  <text x="172" y="98" text-anchor="middle" font-size="10" fill="#64748b">P0</text>
  <text x="378" y="98" text-anchor="middle" font-size="10" fill="#64748b">P1</text>
  <text x="548" y="98" text-anchor="middle" font-size="10" fill="#64748b">P2</text>
  <rect x="30" y="124" width="180" height="58" rx="8" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="120" y="150" text-anchor="middle" font-size="13" font-weight="700" fill="#115e59">Consumer 1</text>
  <text x="120" y="170" text-anchor="middle" font-size="11" fill="#0f766e">Consumes P0</text>
  <rect x="270" y="124" width="180" height="58" rx="8" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="360" y="150" text-anchor="middle" font-size="13" font-weight="700" fill="#115e59">Consumer 2</text>
  <text x="360" y="170" text-anchor="middle" font-size="11" fill="#0f766e">Consumes P1</text>
  <rect x="510" y="124" width="180" height="58" rx="8" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="600" y="150" text-anchor="middle" font-size="13" font-weight="700" fill="#115e59">Consumer 3</text>
  <text x="600" y="170" text-anchor="middle" font-size="11" fill="#0f766e">Consumes P2</text>
  <text x="360" y="200" text-anchor="middle" font-size="11" fill="#64748b">Each partition is consumed by only 1 consumer → message order within that partition is guaranteed</text>
  <rect x="110" y="218" width="220" height="44" rx="8" fill="#ffedd5" stroke="#f97316"/>
  <text x="220" y="238" text-anchor="middle" font-size="12" font-weight="700" fill="#9a3412">Consumer 2 crashes</text>
  <text x="220" y="254" text-anchor="middle" font-size="11" fill="#c2410c">Triggers rebalance</text>
  <line x1="330" y1="240" x2="386" y2="240" stroke="#475569" stroke-width="1.6" marker-end="url(#kfarr)"/>
  <rect x="390" y="218" width="220" height="44" rx="8" fill="#ccfbf1" stroke="#99f6e4"/>
  <text x="500" y="238" text-anchor="middle" font-size="12" font-weight="700" fill="#115e59">Assigned to Consumer 1 or 3</text>
  <text x="500" y="254" text-anchor="middle" font-size="11" fill="#0f766e">Takes over P2</text>
  <rect x="30" y="278" width="660" height="34" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="360" y="299" text-anchor="middle" font-size="12" fill="#3730a3">Rebalance only reassigns partition ownership; at any given time, each partition is still consumed by only 1 consumer, so order guarantees are unaffected</text>
</svg>

Consumer groups guarantee **ordering**: since each partition has only 1 consumer → the messages for that partition seen by the consumer are ordered.

### Offset Commit

The consumer manages its own offsets—no broker push is required. Typically, offsets are stored in Kafka's internal `__consumer_offsets` topic:

```
Consumer: poll() → fetch N messages → process → commitSync(offsets)
  → enable.auto.commit=false: manual commit (recommended, after successful processing)
  → enable.auto.commit=true: periodic auto-commit (may lose messages)
```

## Log Compaction

Retains the last value based on key, rather than based on time:

```
Log before compaction:
  key=A, value=X
  key=B, value=Y
  key=A, value=Z    ← latest value for key A

Log after compaction:
  key=B, value=Y
  key=A, value=Z

→ Suitable for: KTable (update stream, latest state)
→ Not suitable for: KStream (event stream, each change is an independent event)
```

## References

- **Kafka**: kafka.apache.org/documentation/#design
- **ISR**: kafka.apache.org/documentation/#replication

*Keywords: Kafka, partition, ISR, consumer group, rebalance, offset commit, log compaction*
