Kafka Architecture
Apache Kafka is a distributed event streaming platform used to move data between applications in real time. It handles very large volumes of data quickly and reliably, and is widely used in microservices, data pipelines and real-time analytics.
This guide explains Kafka’s architecture piece by piece: producers, topics, partitions, brokers, replication, the controller, consumers, consumer groups and offsets. It then follows a message through the whole system, with diagrams and Java and Spring Boot examples.
1. What Is Kafka Architecture?
Kafka architecture describes how Kafka’s components work together to collect, store and distribute data. In simple words, Kafka is a central hub: some applications send messages to it, and other applications read those messages whenever they need them.
Kafka is distributed: it runs on several machines that work together as one cluster. That makes it fast, scalable and fault-tolerant.
A helpful picture is a newspaper archive. Reporters (producers) add new articles to sections (topics). Every article is kept in order and stored for a while. Readers (consumers) come at different times and read from wherever they stopped, without removing anything for other readers.
2. The Big Picture
Producers Kafka Cluster Consumers
+--------------------------------------+
Order Service -> | Broker 1 Broker 2 Broker 3 | -> Payment Service
| orders-P0 orders-P1 orders-P2 | (group: payments)
Web Clicks ----> | clicks-P1 clicks-P0 clicks-P2 | -> Analytics Service
+--------------------------------------+ (group: analytics)
|
[ KRaft controllers ]
(cluster metadata, leader election)
Producers write to topics, topics are split into partitions spread across brokers, and consumers in consumer groups read from those partitions. A small group of controllers keeps track of the cluster.
3. Main Components of Kafka Architecture
| Component | What it is | Example |
|---|---|---|
| Producer | An application that sends data to Kafka | An order service sends each new order |
| Topic | A named category or channel for messages | orders, payments, page-views |
| Partition | A part of a topic; topics are split into partitions for parallel processing | orders has 6 partitions |
| Broker | A Kafka server that stores data and serves producers and consumers | broker-1, broker-2, broker-3 |
| Cluster | A group of brokers working together | Three brokers in three availability zones |
| Consumer | An application that reads data from Kafka | A payment service reads orders |
| Consumer group | Consumers that share the work of reading a topic; each message goes to one consumer in the group | Three instances of the payment service |
| Controller | Manages cluster metadata, broker membership and leader election (ZooKeeper in older versions, KRaft today) | Three KRaft controller nodes |
Multiple consumer groups can read the same data independently without affecting each other. For example, the payment service and the notification service each receive every order.
4. What a Kafka Message (Record) Contains
| Part | Purpose | Example |
|---|---|---|
| Key (optional) | Decides which partition the message goes to; messages with the same key stay in order | customer-42 |
| Value | The actual data, often JSON, Avro or Protobuf | {"orderId": "1001", "total": 59.90} |
| Timestamp | When the event happened or was written | 2026-10-05T10:15:00Z |
| Headers (optional) | Extra metadata as key–value pairs | trace-id, event-type |
| Offset | The message’s position in its partition, assigned by Kafka | 15327 |
5. Topics, Partitions and the Commit Log
Each partition is an ordered, append-only log: new messages are always added at the end, and existing messages are never changed. Every message gets the next offset number in its partition.
Partition 0: [0] [1] [2] [3] [4] [5] <- new messages added here
Partition 1: [0] [1] [2] [3] <- new messages added here
Partition 2: [0] [1] [2] [3] [4] <- new messages added here
Order is guaranteed inside one partition, not across partitions.
- Partitions enable parallelism: different partitions can live on different brokers and be read by different consumers at the same time.
- Ordering is guaranteed only within a partition. Use a key, such as the order ID, to keep related messages in the same partition and therefore in order.
- On disk, each partition is stored as a series of segment files, which makes it easy to delete old data in whole files.
Learn more in Kafka Topic and Kafka Partition.
6. Brokers and the Cluster
A broker is a Kafka server. It stores partitions on its disks, accepts writes from producers and serves reads to consumers. A cluster is several brokers working together; production clusters usually have at least three.
- Partitions of a topic are spread across brokers, so the load is shared.
- Clients only need the addresses of one or a few brokers (the bootstrap servers). From any broker, they learn where every partition lives.
- Adding brokers increases capacity; partitions can then be moved onto the new brokers.
See Kafka Broker and Kafka Cluster.
7. Replication: Leaders and Followers
Each partition is copied to several brokers. The number of copies is the replication factor, usually 3. For each partition:
- One replica is the leader, which handles writes and, by default, reads.
- The others are followers, which copy new data from the leader.
- Followers that are fully caught up form the in-sync replicas (ISR).
- If the leader’s broker fails, an in-sync follower becomes the new leader automatically.
Broker 1 Broker 2 Broker 3
orders-P0 LEADER follower follower
orders-P1 follower LEADER follower
orders-P2 follower follower LEADER
Leaders are spread across brokers so every broker shares the work. For a deep dive, see Kafka Fault Tolerance.
8. The Controller: ZooKeeper and KRaft
The controller manages the cluster: it tracks which brokers are alive, stores the metadata about topics and partitions, and elects new partition leaders when brokers fail.
| ZooKeeper mode (older) | KRaft mode (current) | |
|---|---|---|
| Metadata stored in | A separate Apache ZooKeeper cluster | Kafka itself, in an internal metadata log |
| Controller | One broker, elected through ZooKeeper | A small quorum of controller nodes using the Raft protocol |
| Systems to run | Kafka and ZooKeeper | Kafka only |
| Status | Deprecated; removed in Kafka 4.0 | Production-ready since Kafka 3.3; the only mode from Kafka 4.0 |
KRaft makes Kafka simpler to operate and lets clusters handle far more partitions. Learn more in Kafka KRaft and Kafka ZooKeeper.
9. How Producers Write Data
- The producer serializes the key and value into bytes, for example JSON.
- A partitioner chooses the partition: by the key’s hash if there is a key, or spreading messages across partitions if there is not.
- Messages are batched and optionally compressed for efficiency.
- The batch is sent to the leader of the chosen partition.
- The leader appends it to the log; followers copy it.
- The producer receives an acknowledgement according to its
ackssetting (acks=allwaits for all in-sync replicas).
See Kafka Producer for all producer settings.
10. How Consumers and Consumer Groups Read Data
Consumers pull data from Kafka at their own pace; Kafka does not push it. Consumers that share a group.id form a consumer group:
- Each partition is read by exactly one consumer in the group at a time, so each message is processed once per group.
- Adding consumers to a group spreads partitions across them, increasing processing speed, up to one consumer per partition.
- Different groups read the same topic independently: each gets every message.
- If a consumer joins, leaves or crashes, the group rebalances and partitions are reassigned.
orders-P0 orders-P1 orders-P2
Group "payments":
consumer A X X
consumer B X
Group "notifications":
consumer C X X X
Each group receives every message; inside a group, partitions are shared.
See Kafka Consumer for consumer settings and rebalancing.
11. Offsets and Retention
Each consumer group stores its progress as a committed offset per partition, in the internal __consumer_offsets topic. If a consumer restarts, it continues from its last committed offset.
Unlike a traditional message queue, Kafka does not delete messages when they are read. Data stays until the topic’s retention rule removes it:
| Retention type | Setting | Example |
|---|---|---|
| By time | retention.ms | Keep messages for 7 days (the default) |
| By size | retention.bytes | Keep at most 50 GB per partition |
| Log compaction | cleanup.policy=compact | Keep only the latest message for each key, such as the current address of each customer |
Because data is kept, consumers can replay old messages, for example to rebuild a database or fix a bug. See Kafka Offset.
12. How Kafka Architecture Works: Step by Step
- A producer sends a message with key
order-1001to theorderstopic. - The key decides the partition, for example partition 1.
- The message goes to the leader broker of partition 1, which appends it to the log at the next offset.
- Followers on other brokers copy the message.
- The producer receives an acknowledgement.
- Consumers in each interested group fetch the message, process it at their own speed and commit their offset.
- The message stays in the log until retention removes it.
13. A Complete Java Example
This example shows the core parts working together: a producer, a topic with keys, and a consumer in a consumer group. Add the client library first:
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>4.0.0</version>
</dependency>
package com.example.kafka;
import java.util.Properties;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.serialization.StringSerializer;
public class OrderEventProducer {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());
props.put(ProducerConfig.ACKS_CONFIG, "all");
try (KafkaProducer<String, String> producer = new KafkaProducer<>(props)) {
for (int i = 1001; i <= 1005; i++) {
String key = "order-" + i; // same key -> same partition -> kept in order
String value = "{\"orderId\":\"" + i + "\",\"status\":\"CREATED\"}";
RecordMetadata meta = producer.send(new ProducerRecord<>("orders", key, value)).get();
System.out.printf("%s -> partition %d, offset %d%n", key, meta.partition(), meta.offset());
}
}
}
}
order-1001 -> partition 2, offset 0
order-1002 -> partition 0, offset 0
order-1003 -> partition 2, offset 1
order-1004 -> partition 1, offset 0
order-1005 -> partition 0, offset 1
package com.example.kafka;
import java.time.Duration;
import java.util.List;
import java.util.Properties;
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.serialization.StringDeserializer;
public class OrderEventConsumer {
public static void main(String[] args) {
Properties props = new Properties();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "payment-service"); // consumer group
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); // new group: start at the beginning
try (KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props)) {
consumer.subscribe(List.of("orders"));
while (true) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(1));
for (ConsumerRecord<String, String> record : records) {
System.out.printf("partition=%d offset=%d key=%s value=%s%n",
record.partition(), record.offset(), record.key(), record.value());
}
// Offsets are committed automatically by default (enable.auto.commit=true)
}
}
}
}
Start the consumer twice with the same group.id, and Kafka splits the partitions between the two instances. Start it with a different group.id, and that instance receives every message independently.
14. Kafka Architecture in a Spring Boot Application
In Spring Boot, the same architecture takes much less code. Add spring-kafka, then configure the connection:
spring:
kafka:
bootstrap-servers: localhost:9092
producer:
acks: all
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
consumer:
group-id: notification-service
auto-offset-reset: earliest
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
package com.example.shop;
import org.apache.kafka.clients.admin.NewTopic;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.config.TopicBuilder;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Configuration
class TopicConfig {
// Created automatically at startup if it does not exist
@Bean
NewTopic ordersTopic() {
return TopicBuilder.name("orders").partitions(3).replicas(1).build(); // use 3 replicas in production
}
}
@Service
class OrderPublisher {
private final KafkaTemplate<String, String> kafka;
OrderPublisher(KafkaTemplate<String, String> kafka) {
this.kafka = kafka;
}
void orderCreated(String orderId, String json) {
kafka.send("orders", orderId, json); // producer
}
}
@Component
class NotificationListener {
@KafkaListener(topics = "orders", groupId = "notification-service") // consumer group
void onOrder(String json) {
System.out.println("Sending confirmation email for " + json);
}
}
15. The Kafka Ecosystem: Connect, Streams and Schema Registry
| Component | Purpose | Learn more |
|---|---|---|
| Kafka Connect | Moves data between Kafka and other systems, such as databases, search engines and cloud storage, using ready-made connectors | Kafka Connect |
| Kafka Streams | A Java library for processing data in real time: filtering, joining, aggregating and windowing streams | Kafka Streams |
| MirrorMaker 2 | Copies topics between clusters, for example to another region | Kafka MirrorMaker |
| Schema Registry | Stores message schemas (Avro, Protobuf, JSON Schema) so producers and consumers agree on the data format; offered by third parties | — |
| Security | Encryption (TLS), authentication (SASL) and authorization (ACLs) | Kafka Security |
16. Why Kafka Is So Fast
| Technique | How it helps |
|---|---|
| Sequential disk writes | Appending to the end of a log is much faster than random writes, even on ordinary disks |
| Operating system page cache | Recent data is served from memory without extra copies inside Kafka |
| Zero-copy transfer | Data can move from disk to the network without being copied through the application |
| Batching | Many messages are sent and stored together, reducing network and disk overhead |
| Compression | Batches can be compressed (gzip, snappy, lz4, zstd) to save bandwidth and storage |
| Partitioning | Work is spread across many brokers and consumers in parallel |
| Pull-based consumers | Consumers fetch data at their own speed, so slow consumers do not slow down producers |
17. Key Features of Kafka
- High throughput: handles millions of messages per second on a well-sized cluster.
- Scalability: add brokers and partitions to grow capacity without downtime.
- Fault tolerance: data is replicated across brokers to prevent loss.
- Durability: messages are stored on disk and survive restarts.
- Real-time processing: data can be consumed as soon as it is produced.
- Loose coupling: producers and consumers do not know about each other.
- Replay capability: consumers can re-read old messages whenever required.
- Ordering: messages with the same key are kept in order.
18. Example: An Online Shopping Website
Imagine an online shopping website:
- The order service sends each new order to the
orderstopic. - The payment service (group
payments) reads the orders and charges customers. - The notification service (group
notifications) reads the same orders to send emails and text messages. - An analytics service (group
analytics) reads them to update sales dashboards.
+--> [payments] Payment Service
Order Service --> orders -+--> [notifications] Notification Service
+--> [analytics] Analytics Service
All these services work independently, without calling each other directly. A new service, such as fraud detection, can start reading the orders topic tomorrow without any change to the order service. If the notification service is down for an hour, it simply catches up from its last offset when it returns. This makes the system flexible and scalable. See Kafka Use Cases for more examples.
19. Best Practices for Designing with Kafka
- Name topics clearly, for example by domain and event:
orders.created,payments.completed. - Choose partition counts with growth in mind: partitions limit how many consumers in a group can work in parallel.
- Use keys for messages that must stay in order, such as all events of one order.
- Use replication factor 3 and
acks=allfor important data. - Give each application its own consumer group.
- Make consumers idempotent, because messages may be delivered more than once.
- Agree on message formats, ideally with schemas, and keep changes backward compatible.
- Set retention based on how long data may need to be replayed.
- Use KRaft for new clusters.
- Monitor consumer lag, under-replicated partitions and broker health.
20. Summary
Kafka architecture is designed for large-scale, real-time data streaming. Producers send data; topics and partitions organize it as ordered, append-only logs; brokers store it, with replication for safety; a controller, now using KRaft, manages the cluster; and consumers in consumer groups read it at their own pace, tracking progress with offsets. Data stays available for replay according to retention rules. With high throughput, scalability, fault tolerance and loose coupling, Kafka has become a core building block of modern distributed systems.
21. Frequently Asked Questions (FAQ)
Q1. What is Kafka architecture in simple words?
Kafka architecture is the way Kafka’s parts work together. Producers send messages to topics; topics are split into partitions stored on brokers; and consumers read those messages at their own pace.
Several brokers form a cluster, data is copied between them for safety, and a controller keeps everything coordinated.
Q2. What is the difference between a topic and a partition?
- A topic is a named stream of related messages, such as
orders. - A partition is one ordered piece of that topic. A topic with 6 partitions has 6 separate logs, which can live on different brokers and be read in parallel.
Producers and consumers work with topics; Kafka uses partitions internally to scale and order the data.
Q3. Is Kafka a message queue?
Kafka can be used like a queue, but it works differently from a traditional message queue:
| Traditional queue | Kafka | |
|---|---|---|
| After reading | Message is removed | Message stays until retention removes it |
| Many readers | Each message usually goes to one reader | Every consumer group gets every message |
| Replay | Not possible | Consumers can re-read old messages |
That is why Kafka is often described as a distributed commit log or event streaming platform.
Q4. Why does Kafka split topics into partitions?
- Scalability: partitions are spread across brokers, so one topic can use the disk and network of many servers.
- Parallelism: each partition can be read by a different consumer in a group at the same time.
- Ordering: messages in one partition stay in order, so related messages share a key and a partition.
Q5. Does Kafka guarantee message order?
Only within a single partition. Messages in one partition are always read in the order they were written. Across different partitions, there is no global order.
To keep related messages in order, give them the same key, such as the order ID or customer ID. Kafka sends all messages with the same key to the same partition.
Q6. What is a Kafka broker?
A broker is a single Kafka server. It stores partition data on its disks, receives messages from producers, serves messages to consumers and replicates data to and from other brokers.
A cluster usually has three or more brokers. Each broker leads some partitions and follows others, so the work is shared.
Q7. What is a consumer group?
A consumer group is a set of consumers with the same group.id that share the work of reading a topic. Each partition is assigned to one consumer in the group, so each message is processed once per group.
Different applications use different groups, so each application receives all messages independently.
Q8. What happens if there are more consumers than partitions?
The extra consumers sit idle. Within one group, a partition can be read by only one consumer at a time, so a topic with 4 partitions can keep at most 4 consumers in a group busy.
Idle consumers are still useful as standbys: if an active consumer fails, they take over its partitions. To scale further, the topic needs more partitions.
Q9. What is an offset in Kafka?
An offset is the position number of a message in its partition: 0, 1, 2 and so on. Consumers commit the offset they have processed, so after a restart they continue from where they left off.
Offsets also let consumers go back and replay messages by resetting to an earlier position.
Q10. How long does Kafka keep messages?
As long as the topic’s retention settings allow, regardless of whether they were read. The default is 7 days (retention.ms), but it can be hours, months or forever, or limited by size (retention.bytes).
With log compaction, Kafka keeps only the latest message for each key, which is useful for data such as the current state of each customer.
Q11. Does Kafka push messages to consumers?
No. Kafka uses a pull model: consumers ask brokers for new messages by calling poll().
This lets each consumer read at its own speed. A slow consumer simply falls behind (its lag grows) without slowing down producers or other consumers, and it can catch up later.
Q12. What is ZooKeeper used for in Kafka, and is it still needed?
In older Kafka versions, ZooKeeper stored cluster metadata, tracked which brokers were alive and helped elect the controller.
It is no longer needed. KRaft, Kafka’s built-in consensus mode, has been production-ready since Kafka 3.3, and Kafka 4.0 removed ZooKeeper entirely. New clusters should use KRaft.
Q13. What is KRaft?
KRaft (Kafka Raft) is Kafka’s built-in way of managing cluster metadata. A small group of controller nodes stores the metadata in an internal log and agrees on changes using the Raft consensus protocol.
It removes the need for a separate ZooKeeper cluster, simplifies operations and supports far more partitions per cluster.
Q14. How does a producer decide which partition to use?
- If the message has a key, the default partitioner hashes the key, so the same key always goes to the same partition.
- If there is no key, messages are spread across partitions, filling one batch at a time for efficiency.
- A producer can also choose a partition explicitly or use a custom partitioner.
Q15. How many partitions should a topic have?
Enough for your peak parallelism, with some room to grow. A simple rule: at least as many partitions as the maximum number of consumers you expect in one group.
Avoid huge numbers without reason: each partition uses broker resources. Many teams start with 3–12 partitions per topic and increase later if needed, keeping in mind that adding partitions changes which partition each key maps to.
Q16. Why is Kafka so fast?
Kafka combines several techniques:
- Sequential disk writes to append-only logs.
- The operating system’s page cache for recent data.
- Zero-copy transfers from disk to network.
- Batching and compression of messages.
- Partitioning to spread work across brokers and consumers.
Q17. What is the difference between Kafka Connect and Kafka Streams?
- Kafka Connect moves data between Kafka and other systems, such as databases or cloud storage, using ready-made connectors, usually with little or no code.
- Kafka Streams processes data inside your Java application: filtering, transforming, joining and aggregating streams in real time.
A typical pipeline uses Connect to bring data in, Streams to process it, and Connect again to send results out.
Q18. Can Kafka be used for microservices communication?
Yes, it is one of its most common uses. Services publish events, such as OrderCreated, and other services subscribe to them. This keeps services loosely coupled: the publisher does not need to know who listens, and listeners can be offline for a while and catch up later.
For requests that need an immediate answer, services usually still use REST or gRPC alongside Kafka.
Q19. What is the minimum Kafka setup for production?
- At least three brokers, ideally in different availability zones.
- Three KRaft controllers (separate nodes or combined with brokers in small clusters).
- Replication factor 3 and
min.insync.replicas=2for important topics. - Security (TLS and authentication) and monitoring from the start.
Managed services, such as cloud-hosted Kafka, can take most of this operational work off your hands.
Q20. How can I run Kafka locally to learn its architecture?
The easiest way is Docker. A single-node Kafka in KRaft mode can be started with one command:
docker run -d --name kafka -p 9092:9092 apache/kafka:latest
Then create a topic with several partitions, run the Java producer and consumer from this tutorial, and start the consumer twice to watch the partitions being shared within a group.