Skip to main content

Apache Kafka: Event Streaming Architecture & Setup Guide

Apache Kafka is the industry-standard distributed event streaming platform, handling trillions of events per day at companies like LinkedIn, Uber, and Netflix. Build real-time data pipelines and streaming applications with durable, replayable event logs.

✓ Durable event log ✓ Horizontal scalability ✓ Multi-consumer replay ✓ 300+ connectors

What is Apache Kafka?

Apache Kafka is a distributed event store and stream-processing platform. Created at LinkedIn in 2010 and open-sourced in 2011, it is now an Apache top-level project. Unlike a traditional message queue that deletes events after delivery, Kafka persists all events in an ordered, immutable log for a configurable retention period. Any number of independent consumers can read the same events at their own pace, and events can be replayed from any offset.

Kafka's architecture consists of brokers (the servers that store data), topics (logical event streams), partitions (horizontal shards of a topic enabling parallelism), producers (applications that write events), and consumers (applications that read events). As of Kafka 3.3, ZooKeeper is no longer required — the KRaft mode uses Kafka itself for metadata management, simplifying deployment significantly.

Core Architecture

Docker Compose Quickstart

# docker-compose.yml — Kafka + Zookeeper + Schema Registry
version: '3.8'
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:7.6.0
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000

  kafka:
    image: confluentinc/cp-kafka:7.6.0
    depends_on: [zookeeper]
    ports:
      - "9092:9092"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'true'

  schema-registry:
    image: confluentinc/cp-schema-registry:7.6.0
    depends_on: [kafka]
    ports:
      - "8081:8081"
    environment:
      SCHEMA_REGISTRY_HOST_NAME: schema-registry
      SCHEMA_REGISTRY_KAFKASTORE_BOOTSTRAP_SERVERS: kafka:9092

Python Producer & Consumer (confluent-kafka)

# pip install confluent-kafka
from confluent_kafka import Producer, Consumer, KafkaError

# --- Producer ---
producer = Producer({'bootstrap.servers': 'localhost:9092'})

def delivery_report(err, msg):
    if err:
        print(f'Delivery failed: {err}')
    else:
        print(f'Delivered to {msg.topic()} [{msg.partition()}] @ {msg.offset()}')

for i in range(10):
    producer.produce(
        topic='user-events',
        key=f'user-{i}',
        value=f'{"event": "click", "user_id": {i}}',
        callback=delivery_report
    )
producer.flush()

# --- Consumer ---
consumer = Consumer({
    'bootstrap.servers': 'localhost:9092',
    'group.id': 'analytics-consumer-group',
    'auto.offset.reset': 'earliest',
})
consumer.subscribe(['user-events'])

try:
    while True:
        msg = consumer.poll(timeout=1.0)
        if msg is None:
            continue
        if msg.error():
            if msg.error().code() == KafkaError._PARTITION_EOF:
                continue
            raise Exception(msg.error())
        print(f'Key: {msg.key()}  Value: {msg.value()}')
finally:
    consumer.close()

Kafka Connect Source Connector

# Kafka Connect — JDBC Source Connector config (REST API)
# POST http://localhost:8083/connectors
{
  "name": "postgres-source-connector",
  "config": {
    "connector.class": "io.confluent.connect.jdbc.JdbcSourceConnector",
    "connection.url": "jdbc:postgresql://db:5432/mydb",
    "connection.user": "kafka",
    "connection.password": "secret",
    "mode": "incrementing",
    "incrementing.column.name": "id",
    "topic.prefix": "db.",
    "table.whitelist": "orders,customers",
    "poll.interval.ms": "5000",
    "value.converter": "io.confluent.kafka.serializers.KafkaAvroSerializer",
    "value.converter.schema.registry.url": "http://schema-registry:8081"
  }
}

Kafka Streams vs Apache Flink vs Spark Streaming

Feature Kafka Streams Apache Flink Spark Structured Streaming
Processing model True streaming (event-by-event) True streaming Micro-batch (default)
Deployment Library (no cluster needed) Cluster (standalone / k8s) Cluster (Spark)
Source / sink Kafka only Kafka, DB, S3, custom Kafka, S3, Delta Lake, custom
State management RocksDB (built-in) RocksDB / heap (advanced) Checkpointing
Latency Very low (ms) Very low (ms) Low–Medium (seconds)
Best for Kafka-centric microservices Complex stateful streaming Batch + streaming unified

Production Best Practices

Frequently Asked Questions

What are Kafka topics, partitions, and consumer groups?▼

A topic is a named, durable log to which producers write events. Topics are divided into partitions — each partition is an ordered, immutable sequence of records stored on disk. Partitions enable parallelism: multiple consumers can read different partitions simultaneously. A consumer group is a set of consumers that collectively consume all partitions of a topic — Kafka assigns each partition to exactly one consumer in the group at a time. Adding more consumers to a group increases read throughput up to the partition count.

What is Kafka's retention and durability model?▼

Kafka persists all events to disk regardless of whether they have been consumed. Retention is configurable per topic by time (retention.ms, default 7 days) or size (retention.bytes). Unlike a message queue that deletes messages after consumption, Kafka retains all events for the retention period — consumers can replay events by resetting offsets. Durability is achieved through replication: each partition is replicated across multiple brokers (replication.factor). A write is acknowledged only when the configured acks replicas confirm receipt.

What is Kafka Schema Registry and why should I use it?▼

Schema Registry is a separate service (from Confluent) that stores and enforces schemas for Kafka messages — typically Avro, Protobuf, or JSON Schema. Producers register a schema before writing; consumers retrieve the schema to deserialize. This prevents schema drift where a producer changes the message format and silently breaks downstream consumers. Schema Registry enforces compatibility rules (backward, forward, full) — a producer cannot publish a schema that would break existing consumers. It is essential in any production Kafka deployment with multiple teams.

What is Kafka Connect and how does it differ from writing a consumer manually?▼

Kafka Connect is a framework for scalable, fault-tolerant integration between Kafka and external systems using pre-built connectors (JDBC, S3, Elasticsearch, Debezium for CDC, etc.). A connector handles offset management, schema evolution, error handling, and parallel execution automatically. Writing a custom consumer requires implementing all of that yourself. Use Connect when a connector exists for your system — it drastically reduces boilerplate. Write a custom consumer when you need complex business logic, aggregations, or the connector ecosystem lacks your target system.

What is the difference between Kafka and a traditional message queue like RabbitMQ?▼

Traditional message queues (RabbitMQ, ActiveMQ) are designed for task distribution: messages are pushed to consumers and deleted after acknowledgement. Kafka is a distributed log: events are retained for a configurable period regardless of consumption, consumers maintain their own offset state, and multiple independent consumer groups can read the same topic at their own pace. Kafka excels at event streaming, audit logs, event sourcing, and replay scenarios. RabbitMQ excels at low-latency task queues with complex routing (fanout, topic, headers exchanges) and when immediate deletion after processing is desired.

How should I choose the number of partitions for a topic?▼

Partitions determine maximum read parallelism — you cannot have more active consumers in a group than partitions. As a rule of thumb, start with the maximum number of concurrent consumers you expect, or use the formula: partitions = target throughput / throughput per partition. Partitions cannot be reduced after creation (only increased), so start conservatively — Kafka is typically I/O-bound so a few partitions per broker is fine. High-throughput topics (100k+ msg/s) may need 20-50+ partitions. Use Kafka's built-in performance testing tool (kafka-producer-perf-test.sh) to benchmark before production sizing.

Share this tool: X / Twitter LinkedIn
✓ 60,000+ developers use DevPlaybook ★★★★★ 4.8 / 5 on Gumroad ✓ MIT licensed · Instant download ✓ No login required

Related Products

on Gumroad

You Might Also Need

More Free Tools

Enjoying this tool? Get more like it.

Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.

DevPlaybook Pro 7 days free

Unlock AI-Powered Dev Tools

  • ⚡ AI Code Review, Doc Generator & SQL Builder
  • ⚡ All premium templates & early access
  • ⚡ Member discounts on Gumroad products
Start Free Trial →

$9/mo after trial · Cancel anytime

Want the full toolkit?

Get DevPlaybook Pro

Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.

$79
$241 separately Save $162 (67% off)
Get DevPlaybook Pro — $79 →

MIT licensed · Instant download · No subscription

See what's included → Browse all deals →