All Articles
How-toยท6 min read

Set Up Exactly-Once Processing in Kafka Streams

Duplicate or lost records ruin downstream counts. Here is how to configure Kafka Streams for true exactly-once processing.

Part of: Big Data with Hadoop & Spark

If your stream processor sometimes double-counts or drops a record after a crash, you are running at-least-once or at-most-once semantics. Kafka Streams can give you exactly-once โ€” each input record affects the output and state exactly one time, even across failures. Here is how to turn it on and what it actually guarantees.

Enable It

Exactly-once in Kafka Streams is a single configuration flag:

Properties props = new Properties(); props.put(StreamsConfig.APPLICATION_ID_CONFIG, "orders-aggregator"); props.put(StreamsConfig.PROCESSING_GUARANTEE_CONFIG, StreamsConfig.EXACTLY_ONCE_V2); // the modern, efficient version

That one setting wires up transactional writes across your output topics and state stores.

What It Actually Guarantees

Under the hood, Kafka Streams wraps each processing cycle in a transaction: reading input offsets, updating state, and writing output all commit together, or not at all. If the app crashes mid-cycle, the transaction aborts and the whole cycle replays cleanly โ€” no partial writes survive.

The guarantee holds within the Kafka ecosystem: input topics โ†’ processing โ†’ state stores โ†’ output topics. It does not magically extend to an external database you write to as a side effect (see below).

Keep Side Effects Idempotent

Exactly-once covers Kafka reads, state, and Kafka writes. A call to an external system inside your processor is not part of the transaction:

stream.foreach((key, value) -> externalDb.write(value)); // NOT covered

If you must write externally, make that write idempotent โ€” key it so a replay overwrites rather than duplicates. Otherwise a retried transaction re-runs the side effect.

Verify It

Kill the application mid-stream and restart it, then check that downstream counts match the input exactly. Watch the consumer group: offsets should only advance on committed transactions. If counts are correct after a hard crash, exactly-once is working.

Summary

Set PROCESSING_GUARANTEE_CONFIG to EXACTLY_ONCE_V2 and Kafka Streams commits input offsets, state, and output atomically per cycle โ€” a crash replays cleanly with no duplicates or gaps. Just remember the guarantee lives inside Kafka: keep any external side effects idempotent, then crash-test it to confirm your counts hold.

#Kafka#Streaming#Big Data#Reliability

Want to go deeper?

Big Data with Hadoop & Spark

View Course