Message ordering guarantees explained for distributed systems#
Ordering is often assumed but rarely guaranteed. This post breaks down what ordering means in Kafka and how to preserve it in Spring Boot consumers.
Prerequisites#
- Kafka cluster
- Java 17+ with Spring Boot
- Understanding of partitions and consumer groups
What ordering actually means#
Ordering is always scoped to a partition or queue. Once you introduce parallelism, you trade throughput for ordered processing.
- Single partition: total order for the stream.
- Multiple partitions: order is preserved per key, not globally.
- Multiple consumers: order is preserved per assigned partition, not across the group.
Enforcing ordering with partition keys#
Ensure that related events share the same key so they land in the same partition.
1
kafkaTemplate.send("payments", paymentId, payload);
Control consumer concurrency#
Spring Kafka allows concurrent listeners. For strict ordering, set concurrency to 1 and use manual acknowledgments.
1
2
3
4
5
@KafkaListener(topics = "payments", groupId = "payments-service", concurrency = "1")
public void onMessage(String payload, Acknowledgment ack) {
processPayment(payload);
ack.acknowledge();
}
Dealing with retries#
Retries can break ordering when failed messages are retried out of sequence. Prefer a retry topic strategy to maintain ordering within each partition.
Things to remember#
- Ordering is partition-scoped, not global.
- Use consistent partition keys to preserve business ordering.
- Limit consumer concurrency when strict ordering is required.