How does unclean.leader.election.enable interact with min.insync.replicas and acks to position a topic on the consistency-vs-availability spectrum?
answer
- two moments: write-time vs failover
- acks=all + MISR = fail-closed writes
- unclean=false = fail-closed failover
- MISR does NOT block unclean election
- RF=3 / MISR=2 / acks=all / unclean=false = CP
basics
~20 sacks=all + min.insync.replicas controls write-time durability (rejecting writes when too few replicas are in sync); unclean.leader.election.enable controls failover behavior when all ISR are gone. Together false + acks=all + min.insync.replicas>=2 gives a CP topic that fails closed; unclean=true makes it fail open with possible loss.
solid answer
~50 sThese three settings cover two different moments. At write time, a producer using acks=all gets an ack only after all current ISR members store the record, and min.insync.replicas sets the minimum ISR size below which the leader rejects writes with NotEnoughReplicas — so you never accept a write that isn't redundantly stored. At failover time, unclean.leader.election.enable decides what happens when the ISR is empty: stay offline (false) or promote a lagging replica (true). For a strongly consistent (CP) topic you combine acks=all, min.insync.replicas>=2 (with RF=3), and unclean=false — writes fail closed when redundancy is lost and the partition stays offline rather than lose data. Flipping unclean to true makes the same topic AP-leaning: it stays writable through total ISR loss but can silently drop committed records. min.insync.replicas does not by itself prevent unclean election; you need unclean=false for that.
go deeper
Know acks=all and min.insync.replicas are about safe writes; unclean.leader.election is about what happens on failover.
Recite the RF=3/MISR=2/acks=all/unclean=false safe combo and why each is needed.
Articulate that the settings cover two different moments and that MISR does not block unclean election.
Design per-topic policies across the CP-AP spectrum and define the operator runbook for empty-ISR partitions.
## Two distinct moments in a record's life **1. Write/commit time — durability of the acknowledgement.** - `acks=all` (a.k.a. `acks=-1`): the producer waits until **every member of the current ISR** has persisted the record before the broker acks. With `acks=1` only the leader needs it; with `acks=0` no ack at all. - `min.insync.replicas` (broker/topic): the **minimum number of in-sync replicas** required for a write to be accepted. If the live ISR shrinks below this, the leader rejects `acks=all` writes with `NotEnoughReplicasException` / `NotEnoughReplicasAfterAppendException`. This makes writes **fail closed**: better to reject than to accept a record stored on too few replicas. Classic safe config: **RF=3, min.insync.replicas=2, acks=all**. You tolerate one broker down (still 2 in ISR, writes continue) but stop accepting writes if two are down (only the leader left). **2. Failover time — what to do when the ISR is empty.** - `unclean.leader.election.enable=false`: no out-of-sync replica may be promoted. With an empty ISR the partition goes **offline** until an ISR member returns. **Fail closed** on availability. - `unclean.leader.election.enable=true`: promote a lagging survivor. The partition stays available. **Fail open**, accepting possible loss of committed records. ## Why you need both, not one `min.insync.replicas` protects the **write path** but says nothing about leader election. You could have min.insync.replicas=2 and still suffer data loss if unclean election is enabled and all ISR replicas die — the lagging replica gets promoted regardless. Conversely, unclean=false protects **failover** but without acks=all/min.insync.replicas you can still lose data at write time (a record acked by only the leader before it crashes was never committed). ## Positioning a topic | Goal | acks | min.insync.replicas (RF=3) | unclean.leader.election.enable | |------|------|------|------| | Strong consistency (CP) | all | 2 | false | | Max availability (AP) | 1 or all | 1 | true | | Throughput, loss-tolerant | 1 | 1 | true | The **CP** row fails closed on both axes: it rejects writes when redundancy is lost and stays offline rather than electing a behind replica. The **AP** row fails open: it keeps serving through almost any failure but can drop data. ## Operational nuance Leaving unclean=false means you must have a **runbook**: when a partition is offline because the ISR is empty, an operator decides whether to wait for the original replicas or to deliberately force an unclean election (accepting loss) to restore availability. That decision is business-driven, which is exactly why Kafka makes it a config rather than always-on behavior.
- If I set min.insync.replicas=2 and acks=all, am I safe from unclean-election data loss?No. Those protect the write path. If every ISR replica later dies and unclean.leader.election.enable is true, a lagging replica is still promoted and committed records are lost. You also need unclean=false.
- What error does a producer get when the ISR drops below min.insync.replicas with acks=all?NotEnoughReplicasException (or NotEnoughReplicasAfterAppendException if it fails after the leader already appended). The write is rejected so it's never falsely acked.
saying these in an interview costs you the question
- Claiming min.insync.replicas alone prevents unclean leader election — it does not; it only governs write acceptance.
- Saying acks=all guarantees zero loss regardless of unclean setting — acks=all + unclean=true can still lose committed data on total ISR loss.
- Treating these three as redundant rather than covering different moments (write vs failover).