---
title: "Kafka scenarios: 135 interactive simulations"
description: "135 Apache Kafka scenarios you can step through in the browser: replication, consumer groups, transactions, storage, KRaft, failures and disaster recovery."
url: https://monedula.dev/kafka-simulator/scenarios/
---

# Kafka scenarios: 135 interactive simulations

Every scenario has its own page, also served as Markdown at the same path with a .md suffix. Open any of them in the playground: https://monedula.dev/kafka-simulator/playground/

[Kafka errors and symptoms, with the scenario that reproduces each](https://monedula.dev/kafka-simulator/troubleshooting/)

[Kafka configs explained, each with the scenario that shows it](https://monedula.dev/kafka-simulator/configs/)

## Anatomy

- [Kafka topics, partitions and offsets explained](https://monedula.dev/kafka-simulator/scenarios/topic-partition-offset/): A producer writes six keyed records to a 3-partition Kafka topic. Watch each record land in one partition and take the next offset of that partition.
- [Kafka write path: one record from producer to consumer](https://monedula.dev/kafka-simulator/scenarios/write-path/): Follow one record through Apache Kafka on a 3-broker cluster: producer batch, leader append, follower replication, high watermark commit and consumer read.
- [Kafka message keys: how a key picks the partition](https://monedula.dev/kafka-simulator/scenarios/keys-and-partitioning/): The same key always hashes to the same partition, which keeps per-key order. Keyless records use the sticky partitioner and spread over 3 Kafka partitions.
- [Kafka offsets are per partition, not global](https://monedula.dev/kafka-simulator/scenarios/offsets-per-partition/): Two partitions each number their records from offset 0, so a Kafka offset means nothing without its partition, and ordering stops at the partition boundary.
- [Kafka replication factor, leader and follower replicas](https://monedula.dev/kafka-simulator/scenarios/brokers-replicas-leader/): RF=3 keeps three copies of a partition on three brokers. The Kafka leader takes the write, both followers fetch it, and the record commits on the full ISR.
- [Kafka high watermark vs log end offset (LEO)](https://monedula.dev/kafka-simulator/scenarios/leo-vs-hw/): Three records reach the leader while slow followers sit at LEO 0. The Kafka high watermark, min(LEO) over the ISR, stays at 0, then jumps to 3 as they catch up.
- [Why Kafka consumers cannot read past the high watermark](https://monedula.dev/kafka-simulator/scenarios/consumer-cannot-read-past-hw/): A record on the leader is not yet replicated, so the consumer polls and gets nothing. Kafka consumers only read committed records, below the high watermark.
- [Kafka log start offset: why the earliest offset is not 0](https://monedula.dev/kafka-simulator/scenarios/log-start-offset/): Five records, then a retention.ms sweep deletes offsets 0-2. The Kafka log start offset moves to 3, which is where a consumer reading from earliest now begins.

## Producers & EOS

- [Kafka producer acks=0: fire and forget, silent data loss](https://monedula.dev/kafka-simulator/scenarios/acks-0-fire-and-forget/): With acks=0 the producer never waits for the broker. One record replicates by luck; the next is lost when its Kafka leader dies, and the producer is never told.
- [Kafka producer acks=1: acknowledged by the leader only](https://monedula.dev/kafka-simulator/scenarios/acks-1-leader-only/): With acks=1 the producer is acked once the leader appends, while the high watermark is still 0. A slow follower fetch makes the Kafka durability gap visible.
- [Kafka acks=0 vs acks=1 vs acks=all on a degraded ISR](https://monedula.dev/kafka-simulator/scenarios/acks-tradeoff/): One Kafka partition below min.insync.replicas: acks=all gets NOT_ENOUGH_REPLICAS, acks=1 is acked by the leader alone, acks=0 is lost once the leader dies.
- [Kafka acks=1 data loss: min.insync.replicas does not help](https://monedula.dev/kafka-simulator/scenarios/acks1-durability-gap/): RF=3 and min.insync.replicas=2 look safe, but acks=1 skips the min.ISR check. The leader acks, dies before any follower fetches, and the Kafka record is gone.
- [Kafka linger.ms vs batch.size: when the producer sends](https://monedula.dev/kafka-simulator/scenarios/linger-and-batch-size/): With linger.ms=600 and a 3-record batch.size (real Kafka counts bytes), two records wait out the linger window while a 3-record burst flushes at once.
- [Kafka producer partitioners: keyed, round-robin and sticky](https://monedula.dev/kafka-simulator/scenarios/producer-partitioners/): On a 4-partition Kafka topic: keyed records share a partition by hash, round-robin spreads keyless ones evenly, and sticky fills one partition per batch.
- [Kafka compression.type: fewer, larger producer batches](https://monedula.dev/kafka-simulator/scenarios/compression-and-batch-shape/): The same six-record burst runs twice: uncompressed it takes two produce requests, with compression.type=zstd one Kafka batch holds all six. Order is unchanged.
- [Kafka buffer.memory and max.block.ms: producer backpressure](https://monedula.dev/kafka-simulator/scenarios/backpressure-buffer-memory/): Slow acks fill a 2048-byte buffer.memory, so the third Kafka send blocks for max.block.ms, then fails with a TimeoutException instead of buffering forever.
- [Kafka idempotent producer: retrying NOT_ENOUGH_REPLICAS](https://monedula.dev/kafka-simulator/scenarios/idempotence-retry/): With the ISR below min.insync.replicas, acks=all fails. The idempotent Kafka producer retries until a broker returns, then the record commits exactly once.
- [Kafka enable.idempotence=false: a retry writes a duplicate](https://monedula.dev/kafka-simulator/scenarios/the-duplicate-problem/): An acks=all record commits but its ack is lost. With idempotence off the Kafka producer retries and the broker appends a second copy of the same record.
- [Kafka idempotent producer dedup vs a plain producer](https://monedula.dev/kafka-simulator/scenarios/idempotence-dedup/): One lost ack, two Kafka producers: the idempotent retry is deduped, the plain one writes a duplicate, and a dropped batch trips OUT_OF_ORDER_SEQUENCE_NUMBER.
- [Kafka max.in.flight.requests.per.connection and ordering](https://monedula.dev/kafka-simulator/scenarios/max-in-flight-ordering/): With idempotence off and max.in.flight=2, a retried record lands after a later one: log [A, B, A]. At max.in.flight=1 Kafka keeps produce order.

## Consumer groups

- [Kafka consumer poll loop: subscribe, poll, fetch](https://monedula.dev/kafka-simulator/scenarios/subscribe-poll-fetch-loop/): A single consumer subscribes to a topic and polls in a loop. Each poll fetches the next committed Kafka records and advances its position until it is caught up.
- [Kafka auto.offset.reset: earliest vs latest vs none](https://monedula.dev/kafka-simulator/scenarios/auto-offset-reset/): Two new Kafka consumer groups join a topic holding three records: earliest replays all three, latest reads only new records, and none would raise an error.
- [Kafka committed offsets: enable.auto.commit and restart](https://monedula.dev/kafka-simulator/scenarios/committing-offsets/): A consumer auto-commits after reading three records, crashes, and restarts at offset 3. The Kafka committed offset, not the live position, is the resume point.
- [Replay a Kafka topic: consumed records stay in the log](https://monedula.dev/kafka-simulator/scenarios/replay-rewind-offset/): Kafka keeps consumed records; the committed offset is just a bookmark. Stop the group, reset it to earliest and watch it re-read O1-O3, each delivered twice.
- [Kafka consumer group: how partitions split across members](https://monedula.dev/kafka-simulator/scenarios/partitions-split-across-members/): A two-member Kafka consumer group splits a four-partition topic with the range assignor: c1 owns p0-p1, c2 owns p2-p3, and each partition has exactly one owner.
- [Kafka consumer group rebalance when a consumer joins](https://monedula.dev/kafka-simulator/scenarios/add-consumer-rebalance/): One consumer owns all four partitions, then a second joins. An eager rebalance revokes every partition, then the Kafka group splits them two and two.
- [Kafka partition assignors: range vs round-robin vs sticky](https://monedula.dev/kafka-simulator/scenarios/assignors-range-roundrobin-sticky/): One Kafka group tries three assignors in turn: range assigns contiguous blocks, round-robin interleaves, and sticky keeps the current layout, moving nothing.
- [Kafka eager vs cooperative rebalancing (cooperative-sticky)](https://monedula.dev/kafka-simulator/scenarios/rebalance-protocols/): A join under the range assignor revokes every partition. Under cooperative-sticky (KIP-429) only p1 moves while the rest of the Kafka group keeps consuming.
- [Kafka consumer crash and session.timeout.ms](https://monedula.dev/kafka-simulator/scenarios/consumer-crash/): A crashed Kafka consumer keeps its partition, which stalls while the other member consumes, until session.timeout.ms evicts it and the survivor takes over.
- [Kafka max.poll.interval.ms: evicting a stuck consumer](https://monedula.dev/kafka-simulator/scenarios/max-poll-interval/): A stuck consumer still heartbeats, so session.timeout.ms never fires. Its partition lags until max.poll.interval.ms expires and the consumer leaves the group.
- [Kafka static membership: group.instance.id avoids rebalances](https://monedula.dev/kafka-simulator/scenarios/static-membership/): Two groups lose a member at once. The static member rejoins within session.timeout.ms and keeps its partition; the dynamic one is evicted and Kafka rebalances.
- [Kafka consumer lag: why it grows and how it drains](https://monedula.dev/kafka-simulator/scenarios/sustained-lag/): max.poll.records=2 caps a consumer below the producer rate, so Kafka consumer lag builds and holds near its peak, then drains once the producer stops.
- [Evicted Kafka consumer: how a survivor takes its partition](https://monedula.dev/kafka-simulator/scenarios/evicted-member-ghost/): A three-member group loses c2 and its partition stalls. At session.timeout.ms Kafka evicts it and an incremental rebalance hands p1 to c1, which drains it.

## Replication

- [Kafka ISR (in-sync replicas): how replicas leave and rejoin](https://monedula.dev/kafka-simulator/scenarios/the-isr-set/): A broker dies and the Kafka ISR shrinks from {1,2,3} to {1,2}. Writes still commit at min.insync.replicas=2, then the broker restarts, back-fills and rejoins.
- [min.insync.replicas with acks=all: when Kafka refuses writes](https://monedula.dev/kafka-simulator/scenarios/min-isr-boundary/): Brokers fail one by one under min.insync.replicas=2. Writes still commit at ISR 2, then Kafka rejects the next acks=all write with NOT_ENOUGH_REPLICAS at ISR 1.
- [Kafka slow follower: replica.lag.time.max.ms and the ISR](https://monedula.dev/kafka-simulator/scenarios/slow-follower/): A throttled follower lags past replica.lag.time.max.ms and drops out of the Kafka ISR without crashing, then rejoins on its own once it catches up.
- [Kafka high watermark pinned by a slow in-sync replica](https://monedula.dev/kafka-simulator/scenarios/hw-recompute-on-isr-shrink/): A throttled broker stays in the ISR at LEO 0, pinning the Kafka high watermark at 0 while two replicas hold the data. Once it drops out, the HW jumps to 3.
- [Losing two Kafka brokers with min.insync.replicas=2](https://monedula.dev/kafka-simulator/scenarios/losing-two-brokers/): An RF=3 acks=all partition loses broker-2, re-elects a leader and keeps writing. Losing broker-3 drops the Kafka ISR below the floor until broker-2 restarts.
- [Kafka preferred leader election after a rack failure](https://monedula.dev/kafka-simulator/scenarios/leader-balancing/): A rack dies and leadership piles onto the surviving brokers. It stays skewed after the rack returns, until a Kafka preferred-leader election spreads it back.
- [Kafka unclean.leader.election.enable: offline or data loss](https://monedula.dev/kafka-simulator/scenarios/unclean-leader/): The whole ISR is dead and unclean election is off, so the Kafka partition stays offline. Turn the flag on and a stale replica leads, losing 3 committed records.
- [Kafka unclean leader election: permanent loss of acked data](https://monedula.dev/kafka-simulator/scenarios/unclean-election-data-loss/): With unclean.leader.election.enable=true in the topic config, a stale replica is promoted on its own and three acked Kafka records are lost for good.
- [Kafka log truncation when an old leader returns](https://monedula.dev/kafka-simulator/scenarios/returning-replica-truncation/): Two uncommitted records sit only on the leader when it is cut off. A new Kafka leader takes over at HW 2, and the old one truncates them before rejoining.
- [Kafka broker.rack: rack-aware replica placement](https://monedula.dev/kafka-simulator/scenarios/rack-aware-placement/): With broker.rack set, each partition keeps one replica in each of three racks. Lose a whole rack and Kafka acks=all writes still commit with 2 in-sync replicas.
- [Kafka rack-aware reassignment after adding a rack](https://monedula.dev/kafka-simulator/scenarios/rack-rebalance/): With two racks, RF=3 puts two replicas in one rack. A broker joins rack-c, and a rack-aware reassignment spreads each Kafka partition across all three racks.
- [Increase the replication factor of an existing Kafka topic](https://monedula.dev/kafka-simulator/scenarios/change-replication-factor/): RF goes from 2 to 3 through a partition reassignment. The new replica on broker-3 starts empty, back-fills the log and joins the ISR, with no Kafka downtime.

## Transactions

- [Kafka at-most-once vs at-least-once vs exactly-once](https://monedula.dev/kafka-simulator/scenarios/delivery-contracts/): Three producers, one Kafka partition, one fault: a lost ack duplicates at-least-once, idempotence dedups exactly-once, acks=0 loses a record to a dying leader.
- [At-least-once delivery in Kafka: where duplicates come from](https://monedula.dev/kafka-simulator/scenarios/where-duplicates-come-from/): ORDER-42 is stored and replicated, but the ack is lost. Unable to tell a lost ack from a lost write, the producer retries and Kafka appends the order twice.
- [Kafka transaction commit vs abort with read_committed](https://monedula.dev/kafka-simulator/scenarios/txn-commit-vs-abort/): Two transactions on one Kafka partition: a commit moves the last stable offset so read_committed reads the batch; an abort marks the range and it is skipped.
- [Kafka isolation.level: read_committed vs read_uncommitted](https://monedula.dev/kafka-simulator/scenarios/transactions-read-committed/): One transaction commits across two partitions, a second aborts. Compare what Kafka read_committed and read_uncommitted consumers see at each step.
- [Kafka last stable offset (LSO) with concurrent transactions](https://monedula.dev/kafka-simulator/scenarios/concurrent-txn-lso/): Two producers hold open transactions on one partition. The younger one commits first, but the Kafka LSO does not move until the older one commits too.
- [Kafka transaction.timeout.ms: the coordinator aborts](https://monedula.dev/kafka-simulator/scenarios/txn-timeout/): A transaction is never resolved. After transaction.timeout.ms the Kafka coordinator aborts it, releases the LSO and fences the producer with an epoch bump.
- [Kafka read_committed during a leader election](https://monedula.dev/kafka-simulator/scenarios/read-committed-during-election/): An open transaction pins the LSO below the high watermark when the leader dies. The new Kafka leader keeps that LSO, and read_committed waits for the commit.
- [Kafka consume-process-produce loop with exactly-once](https://monedula.dev/kafka-simulator/scenarios/consume-process-produce/): Poll orders-in, write to orders-out inside a transaction and stage input offsets with sendOffsetsToTransaction. Kafka commits output and offsets atomically.
- [Kafka zombie producer fencing with transactional.id](https://monedula.dev/kafka-simulator/scenarios/eos-fencing/): A transactional producer commits output and input offsets together. A stale-epoch zombie with the same transactional.id tries to write, and Kafka fences it.
- [Kafka processing.guarantee=exactly_once_v2 end to end](https://monedula.dev/kafka-simulator/scenarios/exactly-once-v2-end-to-end/): Idempotent output, output plus offsets in one transaction, and a fenced zombie producer: the three guarantees of Kafka exactly_once_v2 on one pipeline.

## Storage

- [Kafka retention.ms and a consumer that falls behind](https://monedula.dev/kafka-simulator/scenarios/time-retention/): Retention deletes offsets 0-1 while a group is down. Its next poll hits OFFSET_OUT_OF_RANGE and auto.offset.reset=earliest jumps it to the new Kafka log start.
- [Kafka retention.bytes: size-based log retention](https://monedula.dev/kafka-simulator/scenarios/size-retention/): A 3072-byte retention.bytes cap fits three records. Whenever the log outgrows it, Kafka deletes the oldest records, however recent, and the log start moves up.
- [Kafka OFFSET_OUT_OF_RANGE with auto.offset.reset=none](https://monedula.dev/kafka-simulator/scenarios/offset-out-of-range/): Retention deletes offsets 0-2 while a group is offline. Its Kafka fetch from offset 0 is then out of range, and with auto.offset.reset=none the group is stuck.
- [Kafka log compaction: cleanup.policy=compact explained](https://monedula.dev/kafka-simulator/scenarios/compaction/): Six records, three keys, one tombstone. Kafka compaction keeps the latest value per key, leaves offset gaps and purges the tombstone after delete.retention.ms.
- [Kafka tombstones: deleting a key with delete.retention.ms](https://monedula.dev/kafka-simulator/scenarios/tombstones-delete-retention/): A value=null tombstone for user-2 survives compaction for the delete.retention.ms grace window so Kafka consumers see the delete, then it is purged.
- [Kafka cleanup.policy=compact,delete: both policies at once](https://monedula.dev/kafka-simulator/scenarios/compact-delete-policy/): Compaction removes the stale A=a1 while retention.ms deletes B=b1 by age, though b1 is the latest value of B. The two Kafka cleanups run independently.
- [Kafka tiered storage: offloading old segments to remote](https://monedula.dev/kafka-simulator/scenarios/tiered-storage/): With remote.storage.enable (KIP-405), Kafka moves offsets 0-9 to remote storage: localStartOffset rises to 10, logStartOffset stays 0 and nothing is deleted.
- [Kafka tiered storage: a consumer reads from the remote tier](https://monedula.dev/kafka-simulator/scenarios/reading-from-remote-tier/): A lagging consumer polls from offset 0, below localStartOffset 6, so offsets 0-5 come from remote storage and 6-8 from local disk, as one Kafka log.
- [Kafka local.retention.ms vs retention.ms in tiered storage](https://monedula.dev/kafka-simulator/scenarios/local-vs-total-retention/): local.retention.ms offloads old segments to remote, retention.ms deletes the oldest: one Kafka partition ends with deleted, remote-only and local ranges.
- [Diskless Kafka topics (KIP-1163): the write path](https://monedula.dev/kafka-simulator/scenarios/diskless-write-path/): KIP draft: two producers share one WAL object in object storage, a coordinator assigns offsets at commit, and Kafka replicas read the data back.
- [Diskless vs classic Kafka: cross-AZ replication traffic](https://monedula.dev/kafka-simulator/scenarios/no-cross-az-replication/): KIP draft: three records each on a classic and a diskless Kafka topic across three AZs. Classic costs 7 cross-AZ hops, diskless 0: replicas read object storage.
- [Diskless Kafka produce latency: the price of object storage](https://monedula.dev/kafka-simulator/scenarios/diskless-produce-latency/): KIP draft: in this simulator acks=all is acked in 300 ms on a classic Kafka topic, 1300 ms on a diskless one, 800 ms for a burst that fills the buffer.

## KRaft

- [What the Kafka controller does when a broker dies](https://monedula.dev/kafka-simulator/scenarios/controllers-job/): A dead follower only shrinks the ISR; a dead leader makes the KRaft controller elect a new one and bump leaderEpoch. The Kafka controller epoch never moves.
- [Kafka KRaft quorum: losing a majority of controllers](https://monedula.dev/kafka-simulator/scenarios/kraft-quorum/): Lose one of three KRaft voters and Kafka leader elections still work. Lose two and the quorum is gone: the next election freezes until a voter returns.
- [Kafka KRaft controller failover and metadata log catch-up](https://monedula.dev/kafka-simulator/scenarios/controller-failover-catchup/): A restarted KRaft voter replays the __cluster_metadata records it missed, and on failover a Kafka partition election waits until the new controller serves.
- [Kafka ZooKeeper vs KRaft: what freezes leader elections](https://monedula.dev/kafka-simulator/scenarios/zk-vs-kraft/): Under ZooKeeper, another broker takes over from a lost controller. Losing the ensemble majority freezes Kafka leader elections, as a KRaft quorum loss does.

## Operations

- [Add a Kafka broker and reassign partitions onto it](https://monedula.dev/kafka-simulator/scenarios/reassign-scale-out/): A new broker-4 joins empty and stays idle until kafka-reassign-partitions moves two partitions onto it. Each new Kafka replica catches up and joins the ISR.
- [Remove a Kafka broker safely: drain it first](https://monedula.dev/kafka-simulator/scenarios/scale-in-drain-broker/): Move every partition off broker-4 and let the replacements join the ISR. Removing the empty Kafka broker then causes no ISR shrink and no leader election.
- [kafka-reassign-partitions: change a replica set by hand](https://monedula.dev/kafka-simulator/scenarios/partition-reassignment-by-hand/): Rewrite a Kafka partition replica set from 1/2/3 to 2/4/3. Dropping leader broker-1 moves leadership to broker-2; broker-4 joins the ISR once caught up.
- [Kafka replication throttle during partition reassignment](https://monedula.dev/kafka-simulator/scenarios/throttled-reassignment/): A 1536 B/s replication throttle makes a new Kafka replica take about 4 s, not 300 ms, to copy six records: the move is slower but never floods the link.
- [Change Kafka min.insync.replicas at runtime, no restart](https://monedula.dev/kafka-simulator/scenarios/live-config-changes/): With broker-3 down the ISR is 2. Raising min.insync.replicas to 3 live, with no restart, makes Kafka reject the next acks=all write with NOT_ENOUGH_REPLICAS.
- [producer_byte_rate: how a Kafka client quota throttles](https://monedula.dev/kafka-simulator/scenarios/quotas-throttling/): A Kafka producer capped at producer_byte_rate=2048 bursts four records. The simulator throttles it for 1000 ms, not rejecting, and all six land in order.

## Chaos

- [Kafka broker failure: how the partition leader fails over](https://monedula.dev/kafka-simulator/scenarios/single-broker-hard-kill/): Hard-kill the leader of an RF=3, min.insync.replicas=2 Kafka partition. The ISR shrinks to two, broker-2 takes over and both committed records survive.
- [Kafka split-brain: what a network partition does to leaders](https://monedula.dev/kafka-simulator/scenarios/network-partition-split-brain/): A network split cuts leader broker-1 off from the Kafka controller, which fences it and elects broker-2 from the ISR. The old leader can no longer commit.
- [Kafka network partition: the majority side keeps writing](https://monedula.dev/kafka-simulator/scenarios/minority-vs-majority/): Split broker-1 off from brokers 2 and 3 mid-stream. The side still reaching the Kafka controller commits O3 and O4 to HW 4; broker-1 stays frozen at offset 2.
- [Kafka NOT_ENOUGH_REPLICAS: brokers failing one by one](https://monedula.dev/kafka-simulator/scenarios/cascading-isr-loss/): Kill the replicas of an RF=5, min.insync.replicas=3 Kafka partition one by one. Writes commit down to an ISR of 3, then O4 is rejected and the HW freezes.
- [Kafka ISR re-expansion: how a restarted broker catches up](https://monedula.dev/kafka-simulator/scenarios/heal-partition-isr-reexpansion/): A follower is hard-killed while O3 and O4 commit at min.insync.replicas=2. On restart it fetches the two records it missed and only then rejoins the Kafka ISR.
- [Kafka rack failure: why RF=4 on two racks refuses writes](https://monedula.dev/kafka-simulator/scenarios/correlated-rack-failure/): Four replicas on two racks, min.insync.replicas=3. Rack-a fails, taking the leader and a follower, and Kafka rejects the next write with NOT_ENOUGH_REPLICAS.

## Disaster recovery

- [Kafka stretched cluster across two data centers](https://monedula.dev/kafka-simulator/scenarios/stretched-cluster-2-dc/): One Kafka cluster, RF=4 across DC-A and DC-B. While the ISR spans both sites, acks=all writes are durable in both, so losing DC-B costs no committed records.
- [2.5-DC Kafka stretched cluster with a witness site](https://monedula.dev/kafka-simulator/scenarios/stretched-2-5-dc/): A DC-C witness keeps the Kafka quorum when DC-B is cut off, and Confluent Multi-Region Clusters promote the DC-A observer to restore min.insync.replicas=3.
- [3-DC Kafka cluster: the KRaft quorum survives losing a site](https://monedula.dev/kafka-simulator/scenarios/stretched-3-dc/): One KRaft voter per DC. Cut off DC-A and the other two Kafka voters keep a majority, partition 0 moves to broker-2 and all three partitions stay writable.
- [Kafka in two DCs without a witness: KRaft quorum is lost](https://monedula.dev/kafka-simulator/scenarios/2dc-freeze/): Two KRaft voters, one per DC, no witness. When the link fails neither side has a majority, so after broker-1 dies Kafka elects no leader until the split heals.
- [Kafka data center failure: leader failover to the other DC](https://monedula.dev/kafka-simulator/scenarios/losing-a-whole-dc/): Kill the DC that holds the partition leader and a KRaft voter. The dc-c witness keeps a 2-of-3 Kafka quorum, leadership fails over to DC-B and O3 commits there.
- [Kafka network split inside one DC: ISR drops to the floor](https://monedula.dev/kafka-simulator/scenarios/intra-dc-partition-split/): A link fails inside DC-A, cutting broker-2 off from its peers. The Kafka ISR drops to exactly min.insync.replicas=3 and writes continue while DC-B stays whole.
- [Kafka MirrorMaker 2 active-passive DR and replication lag](https://monedula.dev/kafka-simulator/scenarios/dr-mirror/): MirrorMaker 2 copies committed orders records from the primary Kafka cluster to DR asynchronously. Cut the link and lag grows: O4 and O5 exist on primary only.
- [Kafka DR failover with MirrorMaker 2: measuring RPO](https://monedula.dev/kafka-simulator/scenarios/dr-failover/): Fail over to the DR cluster after the mirror link is cut. O4 and O5 never crossed, so RPO is 2 records and the Kafka consumer resumes at offset 3 on dr.
- [Active-active Kafka with MirrorMaker 2 and region topics](https://monedula.dev/kafka-simulator/scenarios/active-active/): West and east each own a region-named topic mirrored to the other. A cut stalls both Kafka mirrors, local writes go on, and after the heal nothing is lost.
- [MirrorMaker 2 offset translation for Kafka consumer failover](https://monedula.dev/kafka-simulator/scenarios/offset-translation-checkpoint/): MM2 checkpoints g1 into the DR Kafka cluster every 1000 ms. Fail over between checkpoints and the consumer resumes at offset 3, not 5, reprocessing two records.
- [Kafka failback after a MirrorMaker 2 DR failover](https://monedula.dev/kafka-simulator/scenarios/failback-after-primary-recovers/): Fail over to DR, write O4 and O5 there, then fail back: the simulator re-syncs them to the recovered Kafka primary. Real MirrorMaker 2 has no failback action.
- [Active-active Kafka DR drill: move clients to the survivor](https://monedula.dev/kafka-simulator/scenarios/active-active-dr-drill/): Lose the west Kafka region, move pw and cg-west to east and keep writing. Ow2 never mirrored, so it is the RPO; when west returns, MM2 delivers it late.
- [Confluent MRC observers: Kafka replicas outside the ISR](https://monedula.dev/kafka-simulator/scenarios/mrc-observers/): Two sync replicas commit in DC-A with min.insync.replicas=2 while a Confluent MRC observer in DC-B trails, so Kafka acks=all writes never wait on the remote DC.
- [Kafka observer lag in Confluent Multi-Region Clusters](https://monedula.dev/kafka-simulator/scenarios/observer-lag/): Five writes commit through the DC-A sync ISR while the Confluent MRC observer in DC-B falls to lag 5, then drains to 0 without slowing the Kafka producer.
- [Kafka observer promotion in Confluent Multi-Region Clusters](https://monedula.dev/kafka-simulator/scenarios/observer-promotion/): Losing the west region drops the ISR below min.insync.replicas=2. Confluent MRC promotes a dr observer to a sync replica and Kafka acks=all writes resume.
- [Confluent MRC observer promotion: losing the Kafka leader DC](https://monedula.dev/kafka-simulator/scenarios/observer-promotion-reachable-leader/): One Confluent MRC cluster, two outages. Lose DC-B and an observer is promoted so Kafka keeps writing; lose the leader DC and O3 fails with NOT_ENOUGH_REPLICAS.
- [Kafka replica placement: durability vs latency across DCs](https://monedula.dev/kafka-simulator/scenarios/durability-vs-latency/): Confluent MRC: a sync replica in each DC adds 200 ms per Kafka ack and survives losing DC-A, while local sync plus an observer acks at 0 ms and goes leaderless.
- [Confluent Cluster Linking: offset-preserving Kafka mirroring](https://monedula.dev/kafka-simulator/scenarios/cluster-linking-offset-preserving/): Confluent Cluster Linking copies a Kafka topic byte for byte at the same offsets into a read-only mirror, syncs consumer offsets as-is, then promotes it.
- [Kafka mirror topics (Confluent): read-only until promoted](https://monedula.dev/kafka-simulator/scenarios/mirror-read-only-promote-writable/): A Confluent Cluster Linking mirror takes writes only from the link. Promotion stops mirroring it, the Kafka topic turns writable and a producer appends D1.
- [Cluster Linking vs MirrorMaker 2 for Kafka replication](https://monedula.dev/kafka-simulator/scenarios/cluster-linking-vs-mm2/): Confluent Cluster Linking mirrors orders at identical offsets with no translation table, while Kafka MirrorMaker 2 re-produces payments and keeps an offset map.
- [Kafka consumer offset sync: Cluster Linking vs MirrorMaker 2](https://monedula.dev/kafka-simulator/scenarios/consumer-offset-sync-link/): Both groups commit offset 3. Confluent Cluster Linking syncs it as-is, Kafka MirrorMaker 2 translates it, and both reprocess commits made after the last sync.
- [Kafka failover and failback with Confluent Cluster Linking](https://monedula.dev/kafka-simulator/scenarios/bidirectional-links-failback/): Switch to the dr mirror, produce O4, switch back. Confluent Cluster Linking reverses the link in place and both Kafka clusters keep identical offsets 0 to 4.

## Tiered storage

- [Kafka tiered storage lifecycle: offload, read back, expire](https://monedula.dev/kafka-simulator/scenarios/confluent-tiered-lifecycle/): With Apache Kafka KIP-405 settings, local.retention.ms=700 offloads old segments, a lagging consumer reads them back and retention.ms=3000 deletes them.
- [Kafka tiered storage with infinite retention (Redpanda)](https://monedula.dev/kafka-simulator/scenarios/infinite-retention-tiered/): With retention.ms=-1 the remote tier keeps everything: old segments offload after 700 ms and a lagging Kafka consumer reads all nine records from remote.

## Schema registry

- [Confluent Schema Registry subjects and versions for Kafka](https://monedula.dev/kafka-simulator/scenarios/subjects-and-versions/): The orders-value subject starts at v1 under BACKWARD compatibility. Two compatible changes in Confluent Schema Registry grow its Kafka schema history to v3.
- [Kafka schema compatibility: BACKWARD vs FORWARD vs FULL](https://monedula.dev/kafka-simulator/scenarios/compatibility-modes/): Confluent Schema Registry rejects a forward-only change under BACKWARD and accepts it under FORWARD; FULL needs both. The Kafka subject orders-value reaches v3.
- [Kafka breaking schema change rejected by Schema Registry](https://monedula.dev/kafka-simulator/scenarios/breaking-change-rejected/): Confluent Schema Registry, set to BACKWARD, refuses a field type change that breaks both directions. The Kafka subject stays at v2, then a compatible v3 passes.

## Authorization (ACLs & RBAC)

- [TopicAuthorizationException: authorizing a Kafka producer](https://monedula.dev/kafka-simulator/scenarios/acls-authorizing-a-producer/): The Kafka authorizer denies by default: producer App:orders-svc fails with TopicAuthorizationException until an ALLOW Write ACL on topic orders is added.
- [Confluent RBAC role bindings for Kafka topics](https://monedula.dev/kafka-simulator/scenarios/rbac-role-bindings/): A role granting Write and Describe on orders does nothing until bound. Bind App:payments-svc to it with Confluent RBAC and the denied Kafka producer can write.

## Share groups

- [Kafka share groups: queue semantics with KIP-932](https://monedula.dev/kafka-simulator/scenarios/share-group-queue/): Two consumers in one Kafka share group read the same partition and acquire different offsets, draining six jobs like a queue with no partition assignment.
- [More Kafka consumers than partitions with share groups](https://monedula.dev/kafka-simulator/scenarios/cooperative-beyond-partitions/): Three share group members poll one partition with max.poll.records=1 and each acquires its own record, so Kafka consumption scales past the partition count.
- [Kafka share group acquisition lock timeout and redelivery](https://monedula.dev/kafka-simulator/scenarios/acquisition-lock-timeout/): In explicit ack mode a share consumer never acks offset 0. Its 900 ms Kafka acquisition lock expires and the record is redelivered with deliveryCount 2.
- [Kafka share consumer acknowledge: accept, release, reject](https://monedula.dev/kafka-simulator/scenarios/acknowledge-accept-release-reject/): One Kafka share consumer acquires three records and acks one of each: accept marks it acked, release makes it available again, reject archives it for good.
- [Kafka share group poison pill: delivery limit and archiving](https://monedula.dev/kafka-simulator/scenarios/share-group-poison-pill/): A record that is never acked is redelivered until the delivery limit of 3. Then the Kafka broker archives it and the other records drain past it.
- [Kafka share.acknowledgement.mode: implicit vs explicit](https://monedula.dev/kafka-simulator/scenarios/implicit-vs-explicit-ack/): Two Kafka share groups, three records. Implicit mode accepts on the next poll; in explicit mode un-acked offset 2 hits its lock expiry and is redelivered.
- [Kafka share.acquire.mode: batch_optimized vs record_limit](https://monedula.dev/kafka-simulator/scenarios/share-batch-optimized/): With max.poll.records=3 and producer batches of two, record_limit spans a batch boundary; batch_optimized stops at it and needs one more Kafka poll to drain.
- [Renew a Kafka share group acquisition lock (KIP-1222)](https://monedula.dev/kafka-simulator/scenarios/renew-acquisition-lock/): A slow handler sends RENEW before its 1000 ms lock expires and keeps the record, while a Kafka share group without renew loses the lock and gets a duplicate.
- [Kafka share group lag: SPSO, SPEO and the acked prefix](https://monedula.dev/kafka-simulator/scenarios/spso-speo-lag/): Ack offsets 0, 1, 3 and 4 but not 2: the share-partition start offset stays at 2 and Kafka reports lag 3 until the gap is acked and SPSO jumps to 5.

## Capstones

- [Kafka exactly-once pipeline that survives a region failover](https://monedula.dev/kafka-simulator/scenarios/exactly-once-payments-pipeline/): One Kafka transaction commits settlements and input offsets together, read_committed hides open ones, and in this run the MM2 failover loses or repeats nothing.
- [Zero data loss through a Kafka DC outage with Confluent MRC](https://monedula.dev/kafka-simulator/scenarios/survive-regional-outage-zero-loss/): With min.insync.replicas=3 across two DCs, cutting off DC-B makes Confluent Multi-Region Clusters promote the DC-A observer, so Kafka writes never stop.
- [Zero-downtime Kafka migration with Confluent Cluster Linking](https://monedula.dev/kafka-simulator/scenarios/migrate-with-cluster-linking/): Mirror live orders into a new cluster at identical offsets, sync the Kafka consumer offset 1:1, then promote the mirror and cut over with no reprocessing.
- [Multi-region active-active Kafka event backbone](https://monedula.dev/kafka-simulator/scenarios/active-active-event-backbone/): Each region writes only its own region-named topic, mirrored both ways. Region-pinned consumers read the global Kafka stream once; a cut only delays it.
- [Tune Kafka throughput: linger.ms, batch.size and zstd](https://monedula.dev/kafka-simulator/scenarios/tune-high-throughput-low-latency/): A six-record burst leaves as one zstd request under linger.ms=600, max.poll.records=2 paces the Kafka consumer, and a Confluent MRC observer trails then drains.

## Terminal ops

- [Kafka from the terminal: hosts, ssh and the KRaft controller](https://monedula.dev/kafka-simulator/scenarios/terminal-hosts-and-ssh/): Play this one in a shell: ssh between brokers, watch ping answer from your own host during a split, and see that a Kafka controller holds no partition data.
- [Diagnose consumer lag with kafka-consumer-groups --describe](https://monedula.dev/kafka-simulator/scenarios/diagnose-lag/): One of two consumers stops polling. Spot its rising LAG in kafka-consumer-groups, name it with --members and keep the Kafka lag table on screen with watch.
- [Kafka log segments on disk: leader vs follower](https://monedula.dev/kafka-simulator/scenarios/partition-on-disk/): Nine records roll three segment files named by base offset. A stalled follower holds less data than the Kafka leader, and retention deletes whole files.
- [Under-replicated vs under-min-ISR partitions in Kafka](https://monedula.dev/kafka-simulator/scenarios/unhealthy-partitions/): Kill one of three brokers and compare the kafka-topics filters: orders sits at min ISR and still takes writes, payments is under min ISR and refuses acks=all.
- [Reset Kafka consumer group offsets with --to-earliest](https://monedula.dev/kafka-simulator/scenarios/reset-offsets/): kafka-consumer-groups --reset-offsets refuses a group with a live member. Stop the consumer, dry-run, then --execute, and watch the group replay from offset 0.
- [Set retention.ms on a live topic with kafka-configs](https://monedula.dev/kafka-simulator/scenarios/change-a-config/): Set retention.ms=60000 on orders with kafka-configs --alter, watch retention delete a whole segment file, then --delete-config to restore the Kafka default.
- [Kafka partition reassignment: execute, throttle, verify](https://monedula.dev/kafka-simulator/scenarios/move-a-partition/): Move orders-0 onto an empty broker-4 with kafka-reassign-partitions under a throttle, confirm with --verify, then run a preferred leader election to finish.
- [Graceful broker shutdown with kafka-server-stop](https://monedula.dev/kafka-simulator/scenarios/stop-a-broker/): Stop broker-2 from its own shell: ssh still connects, its log dirs stay, the Kafka ISR drops to two, acks=all writes go on, and kafka-server-start restores it.
- [Kafka tools on two clusters: --bootstrap-server decides](https://monedula.dev/kafka-simulator/scenarios/two-clusters/): From a DR host, or via --bootstrap-server, kafka-topics --list shows the MirrorMaker 2 mirror primary.orders, not orders, and after failover g1 resumes on dr.
