Topic and Partition
In distributed messaging systems like Apache Kafka, topics and partitions form the absolute core of the data architecture. While a topic provides a logical channel for categorizing data, a partition introduces physical sharding, horizontal scalability, and strict ordering boundaries. Grasping how these two concepts interact is vital for designing robust producers, efficient consumers, and accurate capacity planning.
A topic serves as a logical category or feed name to which messages are sent and from which they are read. Think of it as a namespace rather than a direct storage bucket.
- Producers publish records to a specific topic, and consumers subscribe to topics to read those records.
- Topics can be configured at an individual level, dictating settings such as retention periods, cleanup policies, partition counts, and replication factors.
- Different business domains utilize separate topics to keep data organized—for instance,
order-eventsoruser-logs. - A single topic can be consumed independently by multiple consumer groups simultaneously, meaning messages are never immediately deleted upon being read by just one group.
Creating a topic is typically handled via administrative tools:
bin/kafka-topics.sh --create \
--topic order-events \
--partitions 6 \
--replication-factor 3 \
--bootstrap-server localhost:9092
Partition: The Physical Sharding Unit
While the topic defines the semantic boundary, the partition is the physical realization of that data. Partitions are the fundamental building blocks that enable Kafka to achieve massive horizontal scaling and parallel processing.
- Every partition acts as an append-only commit log file where messages are stored sequentially in the exact order they arrive.
- Within a partition, each message is assigned a unique, monotonically increasing sequence number known as an offset.
- Ordering is strictly guaranteed only within an individual partition; global ordering across multiple partitions is not guaranteed.
- Partitions can be distributed across different cluster brokers, balancing the input/output load.
- Each partition has designated leader and follower replicas to ensure fault tolerance, with followers continuously syncing data from the leader.
For example, if the order-events topic contains 6 partitions (labeled p0 through p5), incoming messages are routed to one of these partitions based on the producer's routing logic.
Producer Routing and Partitioning Strategies
When a producer sends a record, it relies on specific strategies to determine the destination partition:
- Explicit Partition: Directly target a specific partition index.
- Key-based Partitioning: Hash the provided message key and use the modulo operator against the total partition count to choose a destination.
- Round-Robin / Sticky Partitioning: When no key is supplied, messages are distributed evenly across available partitions to balance loads.
A typical Java producer snippet demonstrates key-based routing:
ProducerRecord<String, String> record =
new ProducerRecord<>("order-events", orderId, payload);
producer.send(record);
When the orderId remains identical, subsequent messages route to the same partition, allowing events belonging to that specific order to stay strictly ordered.
Consumer Groups and Partition Assignment
Consumers read data by organizing themselves into consumer groups. The architectural contract governing partition assignment is strict:
- A single partition can be consumed by only one consumer within a specific consumer group at any given moment.
- A single consumer instance can safely read from multiple partitions.
- If the number of active consumers exceeds the total number of partitions, the extra consumer instances remain idle.
- Scaling consumers up or down triggers a rebalance, dynamically redistributing partitions among the remaining active instances.
Consequently, the total count of partitions defines the maximum possible parallel consumption limit for any single consumer group.
Balancing Sequence Boundaries and Parallelism
Kafka deliberately trades global ordering for extreme throughput by restricting order guarantees to the partition level.
- Achieving absolute global order requires reducing the topic to a single partition, which severely sacrifices parallel throughput.
- Achieving entity-specific ordering (such as per-user or per-order) is achieved by utilizing consistent message keys.
- When entity order does not matter, adding more partitions unlocks higher system throughput.
Architects must clearly define ordering requirements before deciding on a final partition count, avoiding the temptation to over-provision partitions without cause.
Capacity Planning and Replication
Determining the correct number of partitions requires evaluating several competing factors:
- Target Throughput: Estimate initial partitions by dividing expected total throughput by the throughput of a single partition.
- Consumer Concurrency: Ensure the partition count matches or exceeds the desired number of concurrent consumer instances.
- Future Growth: Allocate room for scaling, while keeping in mind that excessive partitions introduce overhead regarding file descriptors, memory, metadata synchronization, and rebalance times.
- Immutability: While partitions can generally be scaled upward, reducing a topic's partition count is exceptionally difficult and usually requires creating a new topic and migrating data.
Replication factors secure data durability. Production environments typically enforce a replication factor of 2 or 3, combined with appropriate settings for acks and min.insync.replicas.
Practical Scenario: Order Processing Pipeline
Consider an e-commerce platform requiring strict chronological processing for individual orders, while processing distinct orders concurrently.
Create the topic:
bin/kafka-topics.sh --create \
--topic order-events \
--partitions 6 \
--replication-factor 3 \
--bootstrap-server localhost:9092
Configure the producer to use the orderId as the record key:
bin/kafka-console-producer.sh \
--topic order-events \
--bootstrap-server localhost:9092 \
--property parse.key=true \
--property key.separator=:
Send sample payloads:
order-1001:{"status":"created"}
order-1002:{"status":"created"}
order-1001:{"status":"paid"}
Deploying a consumer group with 6 instances:
bin/kafka-console-consumer.sh \
--topic order-events \
--bootstrap-server localhost:9092 \
--group order-processor \
--from-beginning \
--property print.key=true \
--property key.separator=:
Events sharing the same orderId land in the same partition and process in order, while distinct orders disperse across the 6 available partitions for concurrent execution.
Common Misconceptions
- Topics are not traditional message queues: They support multiple independent subscriber groups rather than a single destructive read queue.
- Offsets are local: Offsets are unique only within a specific partition, not across the entire topic.
- Scaling partitions changes routing: Increasing the partition count alters the hash mapping for existing keys, which can break existing order guarantees if keys are reused carelessly.
- More consumers != more speed: Adding more consumers than partitions results in idle consumer threads rather than increased performance.
Mastering the interplay between topics and partitions allows engineers to effectively tune Kafka clusters for optimal throughput, latency, reliability, and scalability.