These are delivery semantics: what can happen under failure.
At-most-once
Each message is processed zero or one time. Never twice. May be lost.
Example path: commit offset before processing. Crash after commit → message skipped.
At-least-once
Each message is processed one or more times. No silent loss if you retry, but duplicates possible.
Example path: process, then commit offset. Crash after process but before commit → reprocess.
Most pipelines run this way in practice (paired with idempotent sinks).
Exactly-once
Processed once from the application's point of view (no loss, no duplicate side effects).
In Kafka this usually means:
- Idempotent producers
- Transactions (consume-process-produce as one atomic unit)
- Or Kafka Streams exactly-once processing (
processing.guarantee) - Plus an idempotent downstream if you leave Kafka
at-most-once: may lose, never duplicate at-least-once: may duplicate, should not lose exactly-once: neither lose nor duplicate (with correct setup)
Reality check
"Exactly-once" is not magic. It is a carefully configured pipeline. Many teams ship at-least-once + idempotent writes to the database (upsert by event id) and that is enough.
Interview tip: Define all three, say which Kafka features map to EOS, and admit when idempotent sinks are the pragmatic answer.