Apache Kafka — Distributed Messaging System

Kafka is an open-source Distributed Message Storage platform.
Producers append records to topics; consumers read them in order.
Unlike a simple message queue that deletes messages When 1 reader reads the message, Kafka stores Topics(msg1,msg2..) on disk for a configurable time or size — so that consumer can replay a history.
Decouples services at very high throughput, ie Fast producer, slow consumer can be tied to the system.

Requirements

Non Functional

High throughput: Ingest millions of events/sec from many producers without a single bottleneck.
Scalability: Add brokers and partitions horizontally as traffic grows.
Fault tolerance: Survive broker/disk/network failures without losing committed data.
High availability: Keep serving reads/writes when nodes fail (leader election, replicas).
Durability Persist messages to disk; survive process restarts and crashes.
Ordering Preserve order within a partition (global order only if single partition).
Decoupling Producers and consumers evolve independently; no direct coupling.
Replay New or slow consumers can re-read history from a stored log.
Multi-subscriber Many consumer groups read the same topic independently.
Backpressure & retention Buffer spikes; drop or compact old data by policy, not by accident.

Where Kafka Use Cases

Good Fit

Event streaming / log aggregation — app logs, metrics, clickstreams into data lakes.
Microservice decoupling — order placed, payment captured, inventory updated as events.
Change data capture (CDC) — database changes streamed to search indexes or warehouses.
Real-time analytics — Flink/Spark/Kafka Streams processing pipelines.
Replay & reprocessing — rebuild a downstream system from the log after a bug fix.
High-volume pub/sub — many services subscribe to the same topic with separate consumer groups.

Poor fit:

Low-latency RPC — use gRPC/HTTP directly; Kafka adds ms–s latency and batching trade-offs.
Task queues with per-message ack delete — SQS/RabbitMQ patterns; Kafka is a log, not a mailbox.
Small messages, few TPS, simple setup — operational overhead of a cluster may be overkill.
Strict global ordering — only one partition gives global order; multi-partition = per-key or partition order.

Architecture

Cluster of brokers, topics split into partitions, and a special __consumer_offsets topic
Only 1 Topic can be stored in 1 Partition & A topic is spread across many partitions.
Reliable:
  Records/messages(immutable) are appended to a disk and are strictly ordered. Each record gets a monotonic offset (0, 1, 2, …) unique within that partition.
  Consumers track committed offsets so restart continues from last safe position.
  To locate a record you need topic + partition + offset.
Scalable: More nodes/paritions/disks can be added. Producers can batch and compress record
Fault tolerant: Each partition is replicated across brokers (replication factor rf). If a leader fails, a follower from the ISR is elected. Cluster continues serving as long as leaders exist for partitions
Each partition has one leader broker and zero or more follower replicas on other brokers.


struct Message/Payload {
  name
  age
  empId
}
┬────────────────────────────────────────  Kafka Cluser  ──────────────────────────────────────────────────────────┐
|                                                                                                                  |
|   ┬───────────────────────── BROKER-2(master) ────────────────────────────────────┐   ┬─ Broker1(master)──┐      |
|   | ┬────────────────── Partition-1   ────────────────────┐                       |   |                   |      |
|   | | ┬───────────── topic = Employee ──────────────┐     |                       |   ┴───────────────────┴      |
|   | | | msg1->msg2->msg5    msg6->msg9->msg7        |     |                       |                              |
|   | | ┴─────────────────────────────────────────────┴     |                       |                              |
|   | ┴─────────────────────────────────────────────────────┴                       |                              |
|   |                                                                               |                              |
|   |                       ┬────────────────── Partition-2 ────────────────────┐   |                              |
|   |                       | ┬───────────── topic = Orders ─────────────────┐  |   |                              |
|   |                       | | m1 m2 m3 ....                                |  |   |                              |
|   |                       | ┴──────────────────────────────────────────────┴  |   |                              |
|   |                       ┴───────────────────────────────────────────────────┴   |                              |
|   |                                                                               |                              |
|   |              ┬───────────────────────── Partition-n ────────────────────────┐ |                              |
|   |              | ┬───────────────topic = __consumer_offset ────────────────┐  | |                              |
|   |              | |  Consumer_Name  ID    Topic   Committed_Offset  State   |  | |                              |
|   |              | |  Consumer-1     uid1  Orders  Read till ms7     Alive   |  | |                              |
|   |              | |  Consumer-2     uid1  Orders  Read till ms7     Alive   |  | |                              |
|   |              | ┴─────────────────────────────────────────────────────────┴  | |                              |
|   |              ┴──────────────────────────────────────────────────────────────┴ |                              |
|   ┴───────────────────────────────────────────────────────────────────────────────┴                              |
|                                                                                                                  |
┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴
          

Read & Write paths

kafka Write path: Producers Always write to the partition leader. Followers pull from leader via replication.

Read Path: Consumers Always fetch from the partition leader.

Metadata: clients bootstrap from any broker (bootstrap.servers), then use the cluster metadata API to find partition leaders (not by calling ZooKeeper directly in modern clients).

Leader, follower, and ISR
  For each partition replica set, one broker is the leader — all producer writes and consumer reads go to the leader (by default). Followers replicate the log tail from the leader.
  ISR (In-Sync Replicas) is the set of followers caught up within a configurable lag. Only ISR members are eligible to become leader on failover. A leader is always in its own ISR.

Core concepts

Records, messages, and offsets

A record (message) is typically a (key, value, timestamp, headers) byte sequence. Records in a partition are immutable and strictly ordered. Each record gets a monotonic offset (0, 1, 2, …) unique within that partition. To locate a record you need topic + partition + offset. The key is optional; same key → same partition (hash) preserves order per key.

Topics and partitions

A topic is a named stream of records (e.g. orders, payments). Topics are split into partitions for scale. Rule: {1 topic → N partitions}. 1 partiton stores 1 topic

Brokers and cluster

A broker is a Kafka server (default port 9092) that stores partitions on local disk. A cluster is multiple brokers. Kafka is multi-master at the cluster level — any broker can host leaders for different partitions.
Bootstrap broker(s): first address clients connect to; broker returns full metadata (all brokers, topics, partition leaders).

Consumer groups

A consumer group is set of consumers that work together to read topics. 1 consumer is given resonsiblity to read 1 or more topics to partitions.
This helps to avoid all consumers reading same message and hence to scale (up to partition count).


Topic(Orders)
Partition 0(3 messages): A B C
Partition 1(3 messages): D E F
Partition 2(3 messages): G H I

Consumer group(OrderProcessors)
	Consumer 1 reads +--> Partition 0, Partition 2
	Consumer 2 reads +--> Partition 1
Note Consumer 1 never reads Partition-1
        

Offset progress is stored in the internal topic __consumer_offsets (committed offset per group, topic, partition). If a consumer dies, its partitions are rebalanced to surviving members.

High-water mark (HWM)

When consumer/subscriber reads from Leader. Leader never returns messages which have not been replicated to a minimum set of ISRs.
Leader keeps track of highest water mark. Highest watermark is the offset for that partition replication.
Example(in figure below): Leader does not return messages greater than offset=4, as it is the highest offset message that has been replicated to all followers.

Partition replication and high-water mark

Workflow — one message publish and consume

sequenceDiagram
    autonumber
    participant P as Producer
    participant B as Any Broker
(bootstrap) participant L as Partition Leader
Broker 2 participant F as Follower
Broker 1 participant C as Consumer
Group A participant O as __consumer_offsets P->>B: Metadata request — where is topic orders partition 1? B-->>P: Leader = Broker 2 P->>L: Produce record (key=orderId, value=JSON) L->>L: Append to local log segment on disk L->>F: Replicate to follower ISR F-->>L: ACK replication L-->>P: ACK (acks=all) C->>L: Fetch records from offset 42 L-->>C: Batch of records (up to HWM) C->>C: Process business logic C->>O: Commit offset 43

Role of ZooKeeper (and KRaft)

Classic Kafka (with ZooKeeper): ZooKeeper stores cluster metadata — broker registration, topic configuration, partition leader election, controller identity, and ACLs (in older setups). Brokers and the controller watch ZK for changes. Clients do not query ZooKeeper for leaders; they use the Kafka metadata protocol via brokers.

Modern Kafka (KRaft mode, ZooKeeper-less): metadata is stored in an internal Raft quorum (__cluster_metadata). New deployments should plan for KRaft; ZK is deprecated in Kafka 3.x+ and removed in Kafka 4.x. Conceptually the controller still tracks leaders, ISR, and broker membership — the storage layer changed.

Storing messages on disk, log retention, and client quotas

Log segments on disk

Each partition is a directory of segment files (e.g. 00000000000000000000.log). Appends are sequential — fast on HDD/SSD. An index maps offset → file position for fast lookup. Segments are rolled by size (segment.bytes) or time. This design is why Kafka handles very large volumes: it behaves like a distributed commit log, not an in-memory queue.

Log retention

Old data is removed by policy — not when a consumer reads it:
  retention.ms — delete segments older than N milliseconds (default 7 days).
retention.bytes — cap total size per partition.
Compacted topics (cleanup.policy=compact) — keep latest record per key (changelog topics, Kafka Streams state). Tune retention for compliance (keep 90 days) vs cost (short TTL for high-volume telemetry).

Client quotas

Quotas throttle misbehaving clients so one tenant cannot saturate the cluster. Kafka supports producer/consumer byte-rate limits per client ID or user/principal (quota.producer.default, quota.consumer.default). Exceeding quota returns throttle time in responses. Use quotas in multi-tenant platforms and shared clusters.

Message delivery semantics

Semantics Meaning Typical setup
At-most-once Message may be lost; never duplicated. Producer acks=0; consumer commits offset before processing.
At-least-once No loss if committed; duplicates possible on retry. Producer retries + acks=1/all; consumer commits after processing (idempotent handler).
Exactly-once (EOS) Each record processed once end-to-end (within Kafka Streams / transactional producer). Idempotent producer + transactions + read_committed consumers.

Common data issues and how to resolve them

1. Message loss.
Cause: acks=0/1, unclean leader election, producer not retrying. Fix: acks=all, min.insync.replicas=2, disable unclean.leader.election.enable, enable producer retries and idempotence.

2. Duplicate messages.
Cause: at-least-once retries, consumer crash after process but before commit (or vice versa). Fix: idempotent consumers (store processed IDs), idempotent producer, transactional writes, or dedupe in downstream store.

3. Out-of-order delivery.
Cause: multiple partitions, retries, different keys routed to different partitions. Fix: use same key for events that must stay ordered; single partition if global order required; partition count fixed at create time (or use rekeying carefully).

4. Consumer lag growing.
Cause: slow processing, too few consumers, hot partition skew. Fix: scale consumer group (≤ partition count), optimize handler, increase partitions and rebalance keys, monitor records-lag-max.

5. Hot partition / skew.
Cause: poor key choice (null key or constant key). Fix: choose high-cardinality keys; custom partitioner; salting for extreme hotspots.

6. Disk full.
Cause: retention too long, no size cap, replication multiplies storage. Fix: lower retention.ms/bytes, add disks, tiered storage (Kafka 3.x+), compression (compression.type=lz4/zstd).

7. Rebalance storms.
Cause: consumers join/leave frequently, long max.poll.interval.ms exceeded during heavy processing. Fix: static group membership, cooperative rebalancer, increase interval, decouple processing from poll loop.

8. Under-replicated partitions.
Cause: broker down, network issues, disk slow on follower. Fix: restore broker, replace failed disk, rack awareness, alert on ISR shrink; avoid rolling restart of too many brokers at once.