skip to content

How do acks=all and min.insync.replicas work together to provide durability, and how would you configure them with a replication factor of 3?

level: middleimportance: must knowfreq 65%

answer

  1. acks=all → wait for whole ISR
  2. min.insync.replicas → ISR floor for a write
  3. RF=3, MISR=2, acks=all = tolerate 1 loss
  4. ISR<floor → NotEnoughReplicas error
  5. acks=all alone can degrade to 1 copy

basics

~20 s

acks=all makes the producer wait until all in-sync replicas have the record. min.insync.replicas sets how many replicas must be in sync for that write to be allowed. With replication factor 3, set min.insync.replicas=2 and acks=all so you can lose one broker without losing data and without halting writes.

solid answer

~40 s

The two settings are complementary. `acks=all` (producer side) tells the leader to wait for all current in-sync replicas (ISR) before acknowledging. `min.insync.replicas` (broker/topic side) defines the floor: if the ISR has fewer than that many members, the leader rejects acks=all writes with `NotEnoughReplicasException`/`NotEnoughReplicasAfterAppendException` instead of acknowledging a write that wouldn't be safely replicated. Used alone, acks=all would happily acknowledge a write even when the ISR has shrunk to just the leader — min.insync.replicas prevents that silent loss of redundancy. The standard durable config with replication.factor=3 is acks=all + min.insync.replicas=2: it tolerates one broker failure (2 replicas still in sync, writes continue) while guaranteeing every acknowledged record is on at least 2 brokers. Add enable.idempotence=true to avoid duplicates on retries. Setting min.insync.replicas=3 with RF=3 maximizes safety but makes any single broker outage block writes.

go deeper

for a junior

Know acks=all waits for replicas and min.insync.replicas sets how many must be in sync; RF=3 + min.insync=2 + acks=all is the safe combo.

for a middle

Explain why both are needed together and how the canonical config tolerates one broker loss.

for a senior

Reason about the consistency-vs-availability behavior when the ISR shrinks and the trade-offs of min.insync.replicas=3.

for a principal

Set fleet-wide topic defaults, weigh availability impact of high min.insync.replicas, and combine with idempotence/transactions for end-to-end guarantees.

## The two halves **`acks=all` (producer config, also written `acks=-1`)**: the leader will not acknowledge the produce request until **all in-sync replicas** have appended the record. (With `acks=1` only the leader needs it; with `acks=0` the producer doesn't wait at all.) **`min.insync.replicas` (broker default `min.insync.replicas`, or per-topic override)**: the minimum number of replicas that must be **in sync** for an `acks=all` write to be accepted. If the **in-sync replica set (ISR)** drops below this number, the leader refuses the write and returns an error (`NotEnoughReplicasException` before append, `NotEnoughReplicasAfterAppendException` after). ## Why you need both Suppose replication.factor=3 and you only set `acks=all`. If two followers fall behind and get removed from the ISR, the ISR is just `{leader}`. `acks=all` would then acknowledge a write replicated to **one** broker — you've silently lost your redundancy without knowing it. If that one broker then dies, the data is gone. `min.insync.replicas=2` closes this hole: once the ISR shrinks to 1, the broker **rejects** the write rather than acknowledging an unsafe one. The producer gets an error and can retry/alert, but it will never receive a false "durable" acknowledgement. So: **acks=all** decides *whether the producer waits for the ISR*; **min.insync.replicas** decides *how big the ISR must be for that wait to count as durable*. Both are required — acks=all without a sane min.insync.replicas can degrade to single-copy durability. ## The canonical config (RF=3) | Setting | Value | Effect | |---|---|---| | replication.factor | 3 | 3 copies of each partition | | min.insync.replicas | 2 | at least 2 in-sync copies required to accept a write | | acks | all | producer waits for all ISR members | | enable.idempotence | true | de-duplicates retried writes (exactly-once-ish per producer) | This tolerates **one** broker failure: the ISR is still {2 brokers} ≥ 2, so writes continue, and every acknowledged record is on ≥2 brokers. Lose a second broker and writes are rejected (ISR=1 < 2) — Kafka chooses **consistency over availability** here, refusing to accept writes it can't safely replicate. ## Trade-offs - **min.insync.replicas=3 with RF=3**: every write needs all three; maximum durability but **zero** tolerance for a broker being down — any single outage halts writes. - **min.insync.replicas=1**: effectively no protection beyond the leader; not recommended for durable topics. - The setting only bites when combined with `acks=all`; with `acks=1`/`acks=0` it's ignored, because the producer isn't waiting for the ISR anyway. ## Common gotcha People set `acks=all` and think they're safe, leaving `min.insync.replicas=1` (an old default). Under follower lag, that silently degrades to single-copy durability. Always set both together.

  • What happens to producers when the ISR drops below min.insync.replicas?
    acks=all writes are rejected with NotEnoughReplicasException (or NotEnoughReplicasAfterAppendException). Kafka favors consistency over availability — it stops accepting writes it can't safely replicate, and the producer must retry once the ISR recovers.
  • Why is acks=all with min.insync.replicas=1 risky even though both are 'set'?
    If followers fall out of the ISR, acks=all can acknowledge a write replicated to only the leader, silently dropping redundancy. If that broker then fails, acknowledged data is lost. You need min.insync.replicas≥2 to guarantee multiple copies.

saying these in an interview costs you the question

  • Saying acks=all alone guarantees durability regardless of min.insync.replicas.
  • Setting min.insync.replicas=3 with RF=3 without noting that any single broker outage then blocks writes.
  • Thinking min.insync.replicas matters when acks is 1 or 0 — it only applies to acks=all.

context