Home/Learn/Apache Kafka/At-Most-Once Delivery

At-Most-Once Delivery

Intermediate
Delivery Semantics

At-most-once commits offsets before processing; a crash after commit but before processing causes data loss — acceptable for metrics but not for financial or order data.

Overview

At-most-once delivery guarantees that a message will be processed zero or one time — never more than once. The trade-off is that messages can be lost: if a consumer commits its offset before successfully processing the record, and then crashes, the record is never reprocessed. Data loss is accepted in exchange for no duplicates. This is the semantics of enable.auto.commit=true in Kafka — offsets are periodically committed regardless of whether the records in that batch have been fully processed. At-most-once is appropriate for non-critical, high-throughput telemetry where occasional data loss is acceptable and duplicate events would cause more harm than missing ones.

How At-Most-Once Causes Data Loss

At-most-once delivers via commit-before-process:

1. Consumer polls records [100..110]. 2. Consumer immediately commits offset 110 (before processing). 3. Consumer begins processing record 100. 4. Consumer crashes at record 105. 5. On restart, consumer resumes from offset 111 — records 105–110 are **permanently lost**.

With enable.auto.commit=true, the auto-commit timer may fire between poll() and the end of your processing loop, creating the same window.

Java — At-Most-Once Pattern
// At-most-once — commit BEFORE processing (data loss if crash)
Properties props = new Properties();
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false);

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(List.of("metrics"));

while (true) {
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(500));

    // COMMIT FIRST — at-most-once: crash after this but before processing = data loss
    consumer.commitSync();

    for (ConsumerRecord<String, String> record : records) {
        // If we crash here, records are already committed — will NOT be reprocessed
        processMetric(record.value());
    }
}

// enable.auto.commit=true produces the same at-most-once window:
// auto-commit fires after poll() but before processing completes

When At-Most-Once Is Acceptable

At-most-once is the right choice when:

1. **Missing a record is harmless** — metrics, telemetry, analytics aggregations where one missed data point has negligible impact. 2. **Duplicates are MORE harmful than loss** — e.g., real-time dashboards where a duplicate counter increment is visible, but a missing counter is not. Or push notifications where double-sending is worse than missing one. 3. **Maximum throughput is required** — removing the write-then-process round-trip reduces latency.

Never use at-most-once for: financial transactions, order processing, inventory updates, user-facing state mutations.

Java + YAML — At-Most-Once Use Case
// at-most-once use case: metrics/telemetry (loss acceptable)
@KafkaListener(topics = "app-metrics", groupId = "metrics-aggregator")
public void onMetric(AppMetric metric) {
    // If this metric is lost due to consumer restart, it is acceptable
    // Missing one data point in a 1-minute aggregate is negligible
    metricsAggregator.record(metric.getName(), metric.getValue());
}

# application.yml — auto-commit for non-critical consumers
spring:
  kafka:
    consumer:
      enable-auto-commit: true
      auto-commit-interval: 1000  # commit every 1 second

// at-most-once NEVER appropriate for:
@KafkaListener(topics = "payments")
public void processPayment(Payment payment) {
    // A lost payment = unhappy customer + revenue loss
    // MUST use at-least-once with idempotent processing here
    chargeCard(payment);
}

Delivery Semantics Comparison

Understanding all three delivery semantics side-by-side is essential for system design decisions.

Java (comments) — Delivery Semantics Comparison
// Delivery Semantics Comparison:
//
// ┌─────────────────┬──────────────────┬────────────────────────────────────────┐
// │ Semantic        │ Commit Timing    │ Risk                                   │
// ├─────────────────┼──────────────────┼────────────────────────────────────────┤
// │ At-most-once    │ Before process   │ Data loss on crash — no duplicates     │
// │ At-least-once   │ After process    │ Duplicates on crash — no data loss     │
// │ Exactly-once    │ Atomic with work │ Neither — requires transactions/EOS    │
// └─────────────────┴──────────────────┴────────────────────────────────────────┘
//
// In practice:
// At-most-once  → enable.auto.commit=true, or commitSync() before processing
// At-least-once → enable.auto.commit=false, commitSync/Async AFTER processing
// Exactly-once  → Kafka transactions (transactional.id + read_committed) or
//                 Kafka Streams (processing.guarantee=exactly_once_v2)
//
// Default behaviour of Spring @KafkaListener: at-least-once
// (auto-commit is disabled by Spring Kafka by default)

Key Points to Remember

  • 1At-most-once: commit offsets BEFORE processing — crash after commit but before process = data loss, but no duplicates.
  • 2enable.auto.commit=true with a periodic timer creates the at-most-once window automatically.
  • 3Acceptable for: non-critical metrics, telemetry, analytics where occasional loss is negligible.
  • 4Never use for: financial data, order state, inventory, any user-facing mutation.
  • 5Spring Kafka defaults to at-least-once (disables auto-commit); override only intentionally.
  • 6The three semantics compare as: at-most-once (loss OK), at-least-once (duplicate OK), exactly-once (neither, but has overhead).

Interview Questions

Sign in to ask Aria
1

What is at-most-once delivery semantics in Kafka and how is it achieved?

EasyAmazon
2

How does enable.auto.commit=true create an at-most-once delivery window?

MediumFlipkart
3

When would you deliberately choose at-most-once over at-least-once delivery?

MediumUber
4

Compare at-most-once, at-least-once, and exactly-once delivery semantics with their trade-offs.

MediumNetflix
5

What is the default delivery semantic of Spring Kafka @KafkaListener and why?

MediumGoogle

Ask Aria about At-Most-Once Delivery

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…