Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Kafka Idempotent Producer

The idempotent producer prevents duplicate messages caused by producer retries within a single session. This document covers configuration and usage patterns.


Without IdempotenceWith Idempotencesend(msg) → timeoutretry(msg) → successResult: 2 copiessend(msg, seq=5) → timeoutretry(msg, seq=5) → dedupeResult: 1 copy

The idempotent producer assigns sequence numbers to each batch, allowing brokers to detect and reject duplicates.


# Enable idempotent producer (default true in Kafka 3.0+)
enable.idempotence=true

When enabled, these settings are enforced:

ConfigurationRequired ValueReason
acksallDurability across replicas
retries> 0Allow retries
max.in.flight.requests.per.connection≤ 5Maintain sequence ordering

ComponentPurpose
Producer ID (PID)Unique identifier assigned on startup
Sequence NumberPer-partition counter, incremented per batch
EpochFences zombie producers

The broker validates sequences:

ConditionResult
seq == expectedAccept, increment expected
seq < expectedDuplicate, reject
seq > expectedGap, reject

CoveredNot Covered
Retries within sessionProducer restart (new PID)
Network timeoutsMultiple producer instances
Transient broker failuresApplication-level retry

For cross-session or cross-partition atomicity, use transactions.


Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka:9092");
props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true);
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
try (KafkaProducer<String, String> producer = new KafkaProducer<>(props)) {
for (int i = 0; i < 100; i++) {
producer.send(new ProducerRecord<>("events", "key-" + i, "value-" + i),
(metadata, exception) -> {
if (exception != null) {
log.error("Send failed", exception);
}
});
}
}