Apache Kafka is a popular distributed streaming platform that enables real-time data processing and handling. An important aspect of Kafka is its delivery semantics, which determines how messages are shared and processed between brokers, producers, and consumers in distributed systems.
Three primary Kafka delivery guarantees exist at most once, at least once, and exactly once. These guarantees offer a different balance between data reliability and system performance.
This article will explore Kafka delivery semantics, explaining their use cases, limitations, and implementation strategies to ensure a better understanding of how they can be employed in various streaming applications.
Delivery Semantics Overview
Apache Kafka provides different message delivery semantics to cater to various streaming application requirements. These delivery semantics determine how the streaming platform guarantees event delivery from the source to its destination.
The At-Most-Once delivery semantic focuses on avoiding duplication of messages. This approach ensures that a message is either delivered once or not.
This can result in potential data loss since message delivery is not reattempted in case of such a failure. At-Most-Once semantic is suitable for applications where occasional message loss is acceptable, but duplication must be avoided.
At-Least-Once delivery semantic, as the name suggests, guarantees that each message is delivered at least one time. However, it may result in duplicate messages as the producer re-sends a message if an acknowledgement is not received.
This semantic is usually preferred for applications where data loss is not acceptable, but some level of duplication can be tolerated, or extra handling is provided.
Visit Kafka Delivery Semantics in Spring Boot for a more detailed coding tutorial.
Exactly-Once delivery semantic provides the highest guarantee level without data loss or duplication. This approach ensures that each message is delivered exactly one time, even in the case of failures.
To achieve Exactly-Once semantics, Apache Kafka uses a combination of producer settings and Kafka Streams APIs. The producer must set the ‘acks’ property to ‘all’ to ensure all cluster (source) brokers acknowledge the message.
Exactly-Once semantics suits mission-critical applications where data loss and duplication are unacceptable. However, this guarantee comes at the cost of increased latency, reduced throughput and higher complexity since it is much harder to implement.
Understanding the Kafka Producers’
This section will discuss how Kafka Producers play a crucial role in delivering messages, shedding light on key components such as producer configuration and message acknowledgements.
The configuration of a Kafka Producer primarily focuses on its ability to deliver messages reliably, efficiently, and with minimal latency. Key producer configuration properties include:
- bootstrap.servers: List of broker addresses the producer talks to when sending messages.
- key.serializer and value.serializer: Classes used to transform and serialize the key and value data for transmission. Common serializers include StringSerializer and ByteArraySerializer.
- acks: Determines how the producer waits for the broker’s acknowledgement of sent messages, impacting the delivery semantics. There are three possible values: 0 (no acknowledgement), 1 (acknowledge the leader), and all (acknowledge all in-sync replicas).
- buffer.memory: The total memory allocated for the producer’s buffer, used to store unsent messages.
- batch.size: Helps to optimize throughput by grouping messages into batches before sending them to the brokers.
These properties can be fine-tuned depending on the specific requirements of the application and the desired balance between reliability, latency, and throughput. A Kafka Producer example in Spring Boot is available for a more practical approach.
Message acknowledgements play a pivotal role in determining the delivery semantics of Kafka Producers. The acks property, as mentioned earlier, decides the level of acknowledgement required for message delivery:
- Acks param 0: The producer does not wait for any acknowledgement from the broker. At-most-once delivery semantics.
- Acks param 1: The producer waits for acknowledgement from the leader broker only after the message is written to the leader’s log. At least once, semantics.
- Acks param all: The producer waits for acknowledgement of the same message from all in-sync replicas. Exactly-once delivery semantics can be achieved through other mechanisms, such as transactional producers and consumers or Kafka Connect’s automatic offset management.
The chosen acknowledgement level directly impacts message delivery reliability and performance and should be carefully selected based on the desired trade-offs.
Kafka Consumers and Delivery Semantics
Let’s explore Kafka consumers and various delivery semantics that can be achieved by configuring consumers appropriately. We will discuss consumer configuration and offset management in detail.
Kafka consumers can be configured using several settings, such as:
- auto.offset.reset: Controls the starting offset when no initial offset is available or if the current offset does not exist. For example, it can be set to earliest or latest.
- enable.auto.commit: Controls whether the consumer automatically commits offsets. If it is set to true, the consumer will update offsets periodically in the background as it processes messages.
- max.poll.records: Determines the maximum number of records a consumer can fetch from Apache Kafka broker in a single poll request.
By fine-tuning these settings, consumers can achieve different delivery semantics such as at-most-once, at-least-once, and exactly once. A good example is setting enable.auto.commit set to false allows manual offset management, which can help achieve exactly-once semantics under certain conditions.
See this Spring Kafka Consumer tutorial for a more hands-on approach.
Offset management is critical to ensuring that the desired delivery semantics are achieved. For example, in the at least once delivery semantics, the consumer must keep track of the offset of the last processed message and commit it to Apache Kafka periodically.
This ensures that if the consumer fails, it can resume processing from the same transaction it last committed offset and avoid processing duplicate messages.
In the exactly-once delivery semantics, message offset management is even more important, as it requires coordination between the producer and consumer to ensure that all the messages are processed exactly once. Kafka provides a feature called transactional messaging, which allows producers to write transactional messages to multiple partitions atomically and ensure that the consumer consumes them exactly once.
In summary, Kafka offset management is closely related to the message delivery semantics in Kafka, and effective offset management is critical to achieving the desired level of reliability in message processing.
Guaranteeing Message Order
Kafka provides a few key concepts and configurations to guarantee that messages are delivered in the correct order.
First, Kafka organizes messages into topics and partitions. Each partition is an ordered, immutable sequence of records. As a result, messages within a single partition are processed in the order they were written. Producers can control a message’s partition by choosing a partition key that determines the message destination.
Next, let’s talk about idempotent delivery. The idempotent delivery option ensures that resending a message will not result in duplicate entries in the log and that the log order is maintained. This helps in cases where a producer might need to retry sending a message due to potential failures.
A Spring Kafka Idemopotent consumer article contains code examples of handling Kafka idempotency in Java.
Additionally, it’s helpful to consider producer settings. For instance, the max.in.flight.requests.per.connection parameter controls the number of unacknowledged messages that can be sent concurrently. Setting this value to 1 ensures strict ordering by preventing multiple in-flight messages for the same partition.
Lastly, configuring consumer settings can help safeguard message orders. Utilizing the enable.auto.commit parameter in the Kafka consumer allows automatic offset commits at regular intervals. Pairing this with the auto.commit.interval.ms setting helps to fine-tune the commit frequency, further contributing to controlled message order.
By leveraging these features and configurations, Apache Kafka’s messaging system can offer a consistent and reliable message-ordering experience within its streaming platform.
End-to-End Delivery Guarantees
Apache Kafka provides different levels of end-to-end delivery guarantees that ensure that messages are delivered to the intended destination in a reliable and fault-tolerant manner. These delivery guarantees are important for applications requiring high reliability and data integrity.
The end-to-end delivery guarantees in Kafka are closely related to the message delivery semantics, which dictate how messages are delivered from producers to consumers.
The different levels of end-to-end delivery guarantees in Kafka are:
- At most once guarantee: This provides the lowest level of delivery guarantee, where messages may be lost during transportation or processing.
- At least once guarantee: This provides a higher delivery guarantee, where messages are guaranteed to be delivered at least once, but duplicates may occur.
- Exactly once guarantee: This provides the highest delivery guarantee, where messages are guaranteed to be delivered exactly once without duplicates or losses.
Kafka delivery semantics can have various performance implications depending on your chosen setting. The three types of delivery semantics are at-most-once, at-least-once, and exactly-once. Each of these semantics has advantages and trade-offs related to performance, reliability, and complexity.
At-most-once delivery focuses on minimizing latency, ensuring that messages are delivered quickly. However, this comes at the cost of potential data loss, as failed message deliveries are not retried. This delivery semantic is suitable for scenarios where data loss is acceptable, and speed is crucial to your application’s functionality.
On the other hand, at-least-once delivery seeks to provide reliability by ensuring every message is delivered at least once. This increases the chances of processing duplicate data messages and requires deduplication efforts on the consumer side. However, this semantic usually balances performance and reliability better than at-most-once delivery, making it a popular choice in many use cases.
Exactly-once delivery strives to achieve reliability and deduplication, resulting in messages delivered once and only once. Yet, this level of correctness can come with higher latencies, as the system needs to perform additional checks and coordinate between producers, brokers, and consumers. Moreover, enabling exactly-once delivery requires added configurations and potentially more resource consumption.
In summary, each Kafka delivery semantic has its performance implications, and your choice will depend on your application’s specific requirements related to speed, data reliability, and processing complexity.
Use Cases and Trade-offs
In streaming applications, Kafka’s delivery semantics are crucial in ensuring the reliable processing of high-volume data. Some common use cases for Kafka include user activity tracking in eCommerce sites, real-time financial transactions and fraud detection, and autonomous mobile devices requiring real-time processing.
The right delivery semantic is vital for achieving the desired balance between data accuracy and performance. For instance, choosing exactly-once delivery for systems that need utmost data reliability is crucial. Still, it may come with higher latencies and overheads—yet choosing at most or at least once delivery might bring better performance but at the cost of compromising data reliability.
Understanding the trade-offs between these delivery semantics and aligning them with your application’s requirements allows you to make the best choice for your specific use case and ultimately create a responsive and efficient streaming platform.
Daniel Barczak is a software developer with over 9 years of professional experience. He has experience with several programming languages and technologies and has worked for businesses ranging from startups to big enterprises. Daniel in his leisure time likes to experiment with new smart home gadgets and explore the realm of home automation.