Kafka Replication Safety Checker

Paste replication.factor and min.insync.replicas from the broker or topic config, and acks from the producer config, and see exactly how many broker failures the combination survives: how many before writes are refused, and how many before a write you were told had succeeded is gone. The three settings are owned by different people, which is why the combination is wrong so often.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Work out the tolerance. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

Unclean leader election

Availability chosen over durability, which silently discards acknowledged writes

replication.factor=3
min.insync.replicas=2
unclean.leader.election.enable=true

min.insync.replicas equal to the replication factor

Any single broker restart stops writes entirely

replication.factor=3
min.insync.replicas=3
acks=all

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Setting min.insync.replicas equal to the replication factor

    With RF=3 and min.isr=3, one broker restarting stops writes entirely. There is no headroom for routine maintenance.

    Instead:min.isr = RF - 1. With RF=3 that is 2, which tolerates one broker down.

  2. Leaving unclean.leader.election.enable=true

    It allows an out-of-sync replica to become leader, which discards acknowledged writes to restore availability.

    Instead:Leave it false unless availability genuinely outranks durability, and document the choice.

  3. Setting min.insync.replicas without acks=all

    min.isr is only consulted for acks=all writes. With acks=1 it does nothing at all, which is why the setting appears not to work.

    Instead:The two settings are a pair. Neither works alone.

What it works out

The arithmetic is small. Being certain which of the two numbers you are looking at is the part that prevents both the outage and the data loss.

Two numbers, both exact

How many brokers can fail before writes are refused, and how many before a write you were told succeeded is gone. They are different numbers and they move in opposite directions: acks=1 keeps writing through more failures than acks=all, and loses data on the first one.

The min.insync.replicas=replication.factor trap

RF=3 with min.insync.replicas=3 tolerates zero failures. One broker restarting refuses every write to that topic with NotEnoughReplicasException, including during a routine rolling upgrade. It is reached by trying to be safer than RF=3 with min.insync.replicas=2, which is the setting that actually survives a failure.

acks=1 with min.insync.replicas set

min.insync.replicas is only enforced for acks=all and acks=-1. With acks=1 it is never consulted, so the broker config promises two copies and the producer takes one. This is the most common real data-loss configuration in Kafka, because both halves look correct to the person who owns them.

The Kafka 3.0 default change

enable.idempotence became true by default in 3.0, and idempotence forces acks=all. An absent acks therefore means acks=all on a newer client and acks=1 on an older one. Rather than picking one, both readings are worked out and shown, because the file does not say which client you have.

Why this combination is wrong so often

Three settings decide whether a Kafka write survives, and they are owned by different people. replication.factor and min.insync.replicas belong to whoever runs the cluster. acks lives in application code. Neither party sees the other's value, and no single config file shows the problem.

The arithmetic, in one line each

With acks=all, a write is acknowledged only while at least min.insync.replicas replicas are in sync. So writes survive replication.factor minus min.insync.replicas failures, and an acknowledged write sits on min.insync.replicas replicas, which means it survives the permanent loss of one fewer than that.

RF=3  min.insync=2  acks=all
  writes survive 1 failure, refused at 2
  every acknowledged write is on 2 replicas

RF=3  min.insync=3  acks=all
  writes survive 0 failures, refused at 1
  one broker restarting stops the topic

RF=3  min.insync=4  acks=all
  no write is ever accepted

acks=1 makes min.insync.replicas decorative

The broker only checks the in-sync count for acks=all and acks=-1. With acks=1 the leader answers as soon as the message is in its own log, before any follower has a copy, and a leader that dies in that window takes the message with it. The producer has already been told the write succeeded. Nothing logs an error, and the topic still describes itself as having three replicas.

producer: acks=1
broker:   min.insync.replicas=2

what the platform team believes: 2 copies before ack
what actually happens:          1 copy, then ack
what is lost when the leader dies: everything not
  yet replicated, silently

unclean.leader.election.enable overrides all of it

With it on, Kafka may elect a replica that is behind when no in-sync replica is available. The new leader's log becomes the truth and everything the old leader had is discarded, so acknowledged messages disappear and consumers that had read past that offset see it rewind. Turning it off means a partition with no in-sync replica stays offline until one returns, which is the correct trade for anything you cannot lose.

replication.factor is a count, not a failure domain

Three replicas across two racks means one rack holds two of them, so losing that rack is two simultaneous failures rather than one, and the tolerance above no longer applies. Kafka only spreads replicas across racks when broker.rack is set on the brokers. Add racks=N to what you paste here and that arithmetic is done too.

RF=3, min.insync=2, spread over 2 racks

losing one rack removes 2 of the 3 replicas
  1 replica left, below min.insync.replicas
  writes refused, and a write committed on the
  two replicas in that rack is gone

What a config file cannot tell you

Every number here assumes the ISR is full at replication.factor. A follower that exceeds replica.lag.time.max.ms leaves the ISR with no broker failing at all, which moves the whole table up by one. A topic-level override also beats the broker default, and neither the override nor the current ISR is in a properties file. kafka-topics --describe --under-min-isr-partitions names the partitions that are already refusing writes.

More kafka tools

Kafka Confluent Wire Format Decoder The five junk bytes in front of your payload Kafka Key to Partition Mapper Which partition does this key land on? Kafka Topic Name Validator Legal, risky, or 249 characters too long? Kafka Producer Config Linter Will it start, and will it lose a record? Kafka Message Payload Decoder The first five bytes are usually not data Kafka Connect Source Connector Generator tasks.max is a ceiling, not a count Kafka Connect Sink Connector Generator A dead letter queue with no context headers is a pile of records Kafka Connect SMT Chain Builder The order is the transforms list Kafka MirrorMaker 2 Config Generator It renames every topic by default Kafka Partition Reassignment Generator The throttle is not optional Strimzi Kafka Resource Generator Without the cluster label, nothing happens Kafka mTLS Config Generator The certificate is the identity Kafka Schema Registry Config Generator The compatibility direction is your deployment order Kafka Exactly-Once Config Generator Half of it is worse than none Kafka Broker and KRaft Config Generator The internal topics that break a one-broker cluster Kafka Quota Generator Byte rates are per broker, not per cluster Kafka Streams Config Generator application.id is four things at once Kafka Connect Worker Config Generator Security three times, or the tasks fail Kafka Retention and Unit Converter log.retention.hours does not take milliseconds Kafka Timestamp Converter Two sentinels and two meanings Kafka .properties to YAML Converter Dotted keys stay flat Kafka Streams Internal Topic Predictor Create them before Streams does Kafka ACL Generator The grant you forgot is on another resource type Kafka Topic Config Generator min.insync.replicas is the one that matters Kafka client.properties Generator The file every CLI tool asks for Kafka Producer Config Generator No password field, on purpose Kafka Consumer Config Generator The commit mode decides the semantics Kafka Disk and Retention Calculator retention.bytes is per partition Kafka Partition Count Calculator The number you can never reduce Kafka Cluster Sizing Calculator The traffic no client metric shows Kafka Consumer Lag Catch-Up Calculator Whether it ever clears, not just when Kafka Producer Batching Calculator linger.ms=0 still batches Kafka Segment and Index Sizing Why retention.ms is a lower bound Kafka Rebalance Duration Estimator What a rolling restart really costs Kafka Cost Estimator Your rates, so nothing goes stale Kafka Config Explorer by Version The answer depends on the release Kafka Default Config Reference What moved under a config you never edited Kafka OAuth Bearer Token Decoder Will Kafka accept it, and can it refresh Kafka Record Header Viewer Headers are a list, not a map Kafka Topic Regex Subscription Tester Kafka matches the whole name Kafka ACL Permission Matrix Viewer DENY beats every ALLOW Kafka Connect Config Validator The mistakes that raise no error Kafka Consumer Group Id Validator Which broker coordinates the group Kafka Partition Assignment Visualizer Leadership is the load, not replicas Kafka Consumer Assignment Visualizer The three assignors disagree Kafka ZooKeeper to KRaft Config Converter The authorizer class nobody changes Kafka Config to Strimzi Half of it belongs elsewhere Kafka Docker Compose Generator (KRaft) Reachable from inside and outside Kafka JAAS Config Decoder The line that stops SASL working Kafka CRC32C Calculator Which CRC, over which bytes Kafka Config Upgrade Checker What breaks when you upgrade Kafka Kafka Config Diff Which change actually changed something Kafka Consumer Config Linter Why the group rebalances, and where the records went Kafka Avro Schema Validator The defaults Avro accepts and rejects Kafka Schema Compatibility Checker What the registry will say, before you ask it Kafka Avro Schema Diff Which direction each change breaks Kafka Compression Comparison Measured on your bytes Kafka Delivery Semantics Exactly-once has a consumer half Kafka ksqlDB Query Builder It looks like SQL and the rules are not Kafka Connect SMT Predicate Tester negate reads backwards Kafka Streams Topology Viewer Count the repartitions Kafka Connect Pipeline Visualizer The order things really run in Kafka Protobuf Binary Decoder Works without the .proto Kafka Protobuf JSON Converter Why your JSON does not round-trip Kafka Protobuf to Avro Schema What does not survive the conversion Kafka Avro Binary Decoder Wrong schema, no error Kafka Avro JSON Converter Why the console producer rejects your line Kafka Avro Sample Data Generator Records that actually serialize Kafka JSON to Avro Schema What JSON cannot tell you Kafka JSON Schema to Avro What does not survive the conversion Kafka SASL JAAS Generator One login module, four syntaxes Kafka CLI Command Builder kcat is librdkafka, not Kafka

Elsewhere on the site