Kafka replication: how ISR, acks and min.insync.replicas protect data Intermediate
Estimated reading time: 6 min read
The problem
Section titled “The problem”The producer gets “success” for OrderPaid; a few seconds later the broker holding the leader dies and the event is gone. “We have three brokers, so the data is tripled” is not enough.
You need to know the RF, which replicas are keeping up, which acks the producer uses, and whether the cluster accepts writes when only one replica is in sync.
Durability is the combined result of producer config, topic/broker config and cluster health.
Recommended recipe
Section titled “Recommended recipe”For important topics:
| Setting | Value | Kafka default |
|---|---|---|
| Replication factor (RF) | 3 | default.replication.factor=1 |
min.insync.replicas |
2 | 1 |
acks (producer) |
all |
all in the 4.x producer |
unclean.leader.election.enable |
false |
false |
enable.idempotence |
true |
true in 4.x (article) |
The broker defaults (RF=1, min ISR=1) are not durable: an auto-created topic on a default cluster has only one copy. Disable topic auto-creation in production and create topics with an explicit RF=3.
Concepts
Section titled “Concepts”- RF: the number of replicas assigned to each partition; one leader, the rest are followers fetching from the leader. RF is a target, not a promise that all three have the latest record.
- ISR: the set of replicas keeping up with the leader. A follower that does not catch up within
replica.lag.time.max.ms(default 30000 ms) is removed from the ISR, and rejoins once it catches up. acks=all: the leader acks when the entire current ISR has the record, provided the ISR size meetsmin.insync.replicas. It does not wait for replicas that left the ISR.min.insync.replicas: the minimum ISR size to accept anacks=allwrite; below it the broker returnsNOT_ENOUGH_REPLICAS.acks=1: only the leader records it; if the leader dies before followers fetch, data reported as successful is lost.acks=0: the producer does not know whether the broker received it.
The ISR shrinking step by step
Section titled “The ISR shrinking step by step”OrderPaidRF=3, min.insync.replicas=2, ISR = 3 replicas. The leader waits until the whole ISR has the record before acking: the write succeeds.
| RF | ISR | min ISR | acks=all |
|---|---|---|---|
| 3 | 3 | 2 | Accepted |
| 3 | 2 | 2 | Accepted (one replica outside the ISR) |
| 3 | 1 | 2 | Rejected: durability chosen over write availability |
| 3 | 1 | 1 | Accepted, but only one copy: high risk |
With min ISR=1, “all” no longer means three copies. minISR only constrains acks=all writes; producers using acks=1 are not protected, so audit every client’s configuration.
Leader failure and unclean election
Section titled “Leader failure and unclean election”When the leader dies, the controller picks a new leader from the ISR, so no committed record is lost. If the ISR is empty:
| Configuration | Behavior | Trade-off |
|---|---|---|
unclean.leader.election.enable=false (default) |
The partition stays offline until an ISR replica comes back | Lose availability, keep data |
true |
A replica outside the ISR becomes leader | Acked records may be lost |
For money-related data, keep false.
Note for Kafka 4.1+: Eligible Leader Replicas (ELR, KIP-966) is enabled by default on new clusters.
- When the ISR is empty, the controller can pick a leader from the ELR (replicas that left the ISR but are guaranteed to have data up to the high watermark) before considering the partition offline.
- The docs state that the semantics of
min.insync.replicaschange when ELR is enabled.
Check your cluster’s ELR state before reasoning with the table above.
A record becomes visible to regular consumers only once it is replicated to the whole ISR (committed, per the high watermark). A producer timeout does not mean the record was not written: the ack can be lost on the way back, so use an idempotent producer and an event ID.
When to trade off
Section titled “When to trade off”| Goal | Configuration |
|---|---|
| Must not lose (billing, ledger) | RF=3, minISR=2, acks=all, unclean=false |
| Tolerate small loss for faster writes (metrics, logs) | RF=3, acks=1 or minISR=1 |
| 2-broker cluster | minISR=2 with RF=2 blocks writes when one broker is under maintenance; consider 3 brokers |
The cost of acks=all: waiting for followers, so ack latency depends on the slowest replica in the ISR. Measure it on your cluster before committing to an SLA; this article gives no latency numbers because they depend on hardware and network.
Real-world example
Section titled “Real-world example”A model of the configuration conditions (it does not simulate fetches, elections or timeouts; the repo compose has only one broker):
npx --prefix examples ts-node examples/src/kafka-replication/ack-policy-demo.tsOutput for RF=3, minISR=2: eligible at ISR=3, eligible at ISR=2, reject at ISR=1 with acks=-1; the acks=1, ISR=1 line is eligible. A real test needs at least three brokers and stopping them one by one.
Trade-offs
Section titled “Trade-offs”More data safety
- RF lets a partition survive broker failures.
acks=allplus minISR blocks acks with too few in-sync copies.- The ISR is a more specific health signal than the broker count.
Trade-offs
- A high minISR rejects writes early when the cluster degrades.
- More disk, network and ack latency.
- The producer still has to handle timeouts, retries and duplicates.
Production checklist
Section titled “Production checklist”- RF=3,
min.insync.replicas=2for every important topic; disable topic auto-creation. - Producer
acks=allwith idempotence on; audit every client so noacks=1slips in. unclean.leader.election.enable=false.- Spread replicas across different racks/AZs.
- Alerts: under-replicated partitions, ISR size, per-partition produce error rate.
- Be ready to handle
NOT_ENOUGH_REPLICASin the producer: retry with backoff and a deadline, report upstream when the write cannot be made.
Common mistakes
Section titled “Common mistakes”Summary
Section titled “Summary”Self-check: (1) With RF=3, ISR=1, minISR=1, is an acks=all write rejected? (2) Why does minISR=2 not save an acks=1 producer? (3) Does a produce timeout prove the record was not written?