How it works
The explanation, with examples you can run.
acks
acks | The producer waits for | An acknowledged record can be lost if |
|---|---|---|
0 | Nothing; offsets come back as -1 | Anything goes wrong |
1 | The leader to write it to its log | The leader fails before a follower copies it |
all (-1) | Every in-sync replica | All in-sync replicas fail together |
acks=all has been the default since Kafka 3.0. It is only as strong as the in-sync replica set, which is why it is paired with min.insync.replicas (the replication topic).
Batching
The producer keeps a buffer per partition. A batch is sent when it reaches batch.size (16,384 bytes by default) or has waited linger.ms. Kafka 4.0 changed the linger.ms default from 0 to 5 ms because larger batches usually lower overall latency by reducing the work per record. Compression (compression.type: none by default; lz4 or zstd are common choices) is applied per batch, so better batching also compresses better.
Retries and idempotence
retries defaults to the maximum integer, bounded in time by delivery.timeout.ms (120,000 ms): the total time send() may take, including waiting in the buffer and every retry. When it expires, the send fails and your callback must decide what to do.
Retrying is where duplicates come from: the broker may have written the batch and only the response was lost. The idempotent producer (on by default since 3.0, and required for transactions) fixes this. The broker gives each producer an id, the producer numbers its batches per partition, and the broker refuses to append a sequence number it has already written. It also keeps batches in order with up to 5 requests in flight per connection, which is why idempotence requires max.in.flight.requests.per.connection of 5 or less.
A simplified model of the broker's check:
Press Run to see what your code prints, in order.
Runs in this browser, in an isolated frame with no access to this page. console.log, info, warn and error are shown; code runs as a classic script, so use an async function for await.
The real broker tracks sequences per producer id and partition, for the last five batches, and the producer id changes when a non-transactional producer restarts.
A sensible starting configuration
acks=allenable.idempotence=truecompression.type=lz4linger.ms=5delivery.timeout.ms=120000These are mostly the defaults made explicit, which protects you from a library or an old config file silently changing them. Note that a conflicting setting (for example acks=1) quietly disables idempotence unless you set enable.idempotence=true explicitly, in which case the producer refuses to start.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.