---
title: "Kafka Simulator v1.1: Producer-Semantik in Kafka verstehen"
date: 2026-07-14T00:00:00.000Z
author: "michal"
excerpt: "Kafka Simulator v1.1 ergänzt zehn Szenarien zu Producer-Batching, Partitionierung, Komprimierung, Backpressure, Retries und Idempotenz."
---
Was passiert, nachdem ein Kafka-Producer `send()` aufgerufen hat?

Das klingt nach einer einfachen Frage. Der Producer erstellt einen Datensatz, sendet ihn an Kafka und erhält eine Bestätigung.

Zwischen diesen Schritten kann jedoch einiges passieren.

Der Producer kann auf weitere Datensätze warten und einen Batch bilden. Er muss eine Partition auswählen. Er kann den Batch komprimieren. Ist der Broker langsam, kann dem Producer der Pufferspeicher ausgehen. Schlägt ein Request fehl, kann er ihn erneut versuchen. Gelingt der Retry, nachdem der erste Request bereits geschrieben wurde, empfängt Kafka denselben Batch möglicherweise zweimal.

Der [Kafka Simulator](/kafka-simulator/) v1.1 konzentriert sich auf genau diese Producer-Semantik.

Der Release ergänzt **10 neue Szenarien** und bringt den vollständigen Lehrplan damit auf **23 von 125 Szenarien**.

## Was ist in v1.1 enthalten?

Acht der zehn Szenarien konzentrieren sich auf den Producer. Die übrigen zwei erweitern den Log-Anatomie-Track: das Lesen bis zum High Watermark und den Log Start Offset.

Die Producer-Szenarien decken fünf Bereiche ab:

- Batching mit `linger.ms` und `batch.size`,
- Producer-Partitioner,
- Komprimierung,
- Backpressure mit `buffer.memory` und `max.block.ms`,
- Retries und Idempotenz.

Sehen wir uns jeden davon an.

## Batching mit `linger.ms` und `batch.size`

Ein Kafka-Producer sendet nicht zwangsläufig jeden Datensatz in einem eigenen Request.

Datensätze, die derselben Partition zugeordnet sind, können zu einem Batch gesammelt werden. Der Producer sendet den Batch, sobald er voll ist oder die konfigurierte Wartezeit abläuft.

Hier werden zwei Producer-Einstellungen wichtig:

- `batch.size` begrenzt die Größe eines Batches,
- `linger.ms` erlaubt dem Producer, vor dem Senden auf zusätzliche Datensätze zu warten.

Der Kompromiss liegt zwischen Latenz und Durchsatz.

Ein größerer Batch bedeutet in der Regel weniger Requests und bessere Komprimierung. Auf das Füllen des Batches zu warten kann jedoch die Latenz eines einzelnen Datensatzes erhöhen.

Die neuen Szenarien machen dieses Verhalten sichtbar. Du kannst sehen, wann Datensätze in einen Batch aufgenommen werden, was das Senden des Batches auslöst und wie sich das Ändern der Konfiguration auf die vom Client erzeugten Requests auswirkt.

## Producer-Partitioner

Bevor der Producer einen partitionsspezifischen Batch bilden kann, muss er eine Partition auswählen.

Bei Datensätzen mit Schlüssel wird der Schlüssel verwendet, um die Partition zu bestimmen. Datensätze mit demselben Schlüssel landen daher normalerweise in derselben Partition.

Bei Datensätzen ohne Schlüssel ist das Verhalten anders. Der Producer kann Datensätze anhand seiner Partitionierungsstrategie gruppieren, statt die Partition aus einem Schlüssel zu berechnen.

Der Simulator zeigt beide Fälle Schritt für Schritt:

1. der Producer empfängt den Datensatz,
2. der Partitioner wählt eine Partition,
3. der Datensatz wird dem entsprechenden Batch hinzugefügt,
4. der Batch wird an den Leader dieser Partition gesendet.

So lässt sich leichter erkennen, warum die Partitionierung sowohl die Reihenfolge als auch das Batching beeinflusst.

## Komprimierung erfolgt pro Batch

Die Producer-Komprimierung in Kafka wird auf Record-Batches angewendet, nicht unabhängig auf jeden einzelnen Datensatz.

Diese Unterscheidung ist wichtig.

Komprimierung ist in der Regel wirksamer, wenn ein Batch mehrere ähnliche Datensätze enthält. Ein Batch mit nur einem kleinen Datensatz profitiert womöglich kaum von der Komprimierung. Ein größerer Batch mit sich wiederholenden Daten lässt sich deutlich effizienter komprimieren.

Dadurch ist die Komprimierung mit der Batching-Konfiguration verbunden. Einstellungen wie `batch.size` und `linger.ms` können nicht nur die Request-Häufigkeit beeinflussen, sondern auch die Form und Komprimierbarkeit der resultierenden Batches.

Die neuen Szenarien zeigen die unkomprimierten und komprimierten Batch-Größen und machen diesen Zusammenhang so explizit.

## Backpressure mit `buffer.memory` und `max.block.ms`

Was passiert, wenn eine Anwendung Datensätze schneller erzeugt, als Kafka sie annehmen kann?

Der Producer kann nicht unbegrenzt viele ungesendete Datensätze im Speicher halten. Er verwendet einen begrenzten Puffer, der über `buffer.memory` konfiguriert wird.

Wenn im Puffer kein Platz mehr verfügbar ist, kann ein Aufruf von `send()` blockieren, während er darauf wartet, dass Speicher freigegeben wird.

Er wartet allerdings nicht ewig. Die maximale Blockierzeit wird über `max.block.ms` gesteuert.

Daraus ergeben sich zwei mögliche Ausgänge:

- es werden genügend Daten gesendet und bestätigt, wodurch Pufferspeicher frei wird,
- vor dem Timeout wird kein Platz frei, und das Senden schlägt fehl.

Der Simulator verfolgt den Producer-Puffer direkt. Du kannst sehen, wie Speicher belegt wird, wenn Datensätze hinzugefügt werden, und wieder freigegeben wird, sobald Requests abgeschlossen sind.

Besonders nützlich ist das in Kombination mit einem langsamen Broker oder einer Durchsatzquote. Statt Producer-Backpressure als abstraktes Konfigurationsproblem zu behandeln, kannst du zusehen, wie sich der Puffer füllt, und genau den Send-Vorgang erkennen, der blockiert.

## Retries und das Duplikat-Problem

Angenommen, der Producer sendet einen Batch an einen Broker.

Der Broker schreibt den Batch erfolgreich, aber die Bestätigung geht verloren, bevor sie den Producer erreicht.

Aus Sicht des Producers ist der Request fehlgeschlagen. Er kann nicht wissen, ob der Broker die Daten geschrieben hat. Ein Retry ist daher naheliegend.

Wurde der erste Request jedoch erfolgreich geschrieben, kann der Retry denselben Batch erneut anhängen.

Das ist das Duplikat-Problem, das durch mehrdeutige Fehler entsteht.

Das Retry-Szenario zeigt beide Requests:

1. der ursprüngliche Request erreicht den Broker,
2. die Bestätigung geht verloren,
3. der Producer wiederholt den Batch,
4. der Broker empfängt dieselben Datensätze ein zweites Mal.

Ohne Idempotenz können beide Kopien angehängt werden.

## Idempotente Producer-Semantik

Ein idempotenter Producer erlaubt es Kafka, wiederholte Batches zu erkennen.

Kafka weist dem Producer eine Identität zu und verfolgt Sequenznummern für jede Partition unabhängig. Wird ein Batch mit einer Sequenznummer wiederholt, die der Broker bereits verarbeitet hat, kann der Broker ihn bestätigen, ohne die Datensätze erneut anzuhängen.

Die wichtige Unterscheidung liegt zwischen einem Retry und einem echten Duplikat.

Zwei Datensätze können exakt denselben Schlüssel und Wert enthalten und trotzdem zwei separate Datensätze sein, die von der Anwendung absichtlich gesendet wurden. Kafka darf solche Datensätze nicht entfernen.

Idempotenz dedupliziert Retries des Producer-Protokolls. Sie dedupliziert keine Anwendungsdaten anhand ihres Inhalts.

Die neuen Szenarien zeigen:

- Producer-IDs,
- Partitions-Sequenznummern,
- erfolgreiche idempotente Retries,
- echte Duplikat-Datensätze,
- die Erkennung von Sequenzen außerhalb der Reihenfolge.

## Warum ist `max.in.flight.requests.per.connection` wichtig?

Ein Producer kann mehrere Requests gleichzeitig auf ihre Antworten warten lassen.

Das verbessert den Durchsatz, schafft aber auch ein potenzielles Reihenfolgeproblem.

Angenommen, der Producer sendet Batch A und danach Batch B. Batch A schlägt vorübergehend fehl, während Batch B gelingt. Wird A wiederholt, nachdem B bereits geschrieben wurde, können die Datensätze in einer anderen Reihenfolge angehängt werden.

Idempotenz nutzt Sequenznummern, um eine ungültige Reihenfolge zu erkennen.

Der Simulator zeigt das explizit. Du kannst die erwartete Broker-Sequenznummer sehen, die vom eingehenden Batch mitgeführte Nummer und den Punkt, an dem der Broker einen Request außerhalb der Reihenfolge ablehnt.

## Internen Producer-Zustand untersuchen

Die neuen Szenarien stützen sich stark auf den **Inspector** des Simulators, der den internen Zustand von Producern und Partitionen offenlegt, darunter:

- Retry-Zähler,
- Producer-Sequenznummern,
- Broker-Sequenznummern,
- Pufferbelegung.

Normalerweise sind diese Werte hinter Producer-Metriken, Logs und Protokollverhalten verborgen. Im Simulator lassen sie sich direkt untersuchen, während man ein Szenario vor- oder zurückspult.

## Korrekturen am Producer-Modell

Das Hinzufügen der neuen Szenarien machte es auch nötig, das bestehende Producer-Modell präziser zu gestalten.

### Retries werden pro Batch gezählt

Kafka-Retries erzeugen Requests, die Batches von Datensätzen enthalten.

Ein fehlgeschlagener Request sollte daher einen Retry für den gesamten Batch verbrauchen, nicht einen Retry für jeden einzelnen Datensatz darin.

Der Simulator folgt jetzt diesem Modell. Jeder Datensatz aus einem fehlgeschlagenen Batch wird erneut gesendet, während der Retry-Zähler nur einmal weiterzählt.

### Pufferspeicher wird präzise freigegeben

Der Producer-Pufferspeicher wird jetzt freigegeben, sobald Bestätigungen eintreffen.

Das behebt Fälle, in denen der Simulator Backpressure melden konnte, obwohl bestätigte Datensätze ihren Speicher bereits hätten freigeben müssen.

Dasselbe gilt für `max.block.ms`-Timeouts. Läuft ein blockierter Send-Vorgang ab, wird die zugehörige Pufferbelegung bereinigt.

### `acks=all` wird pro Partition verfolgt

Kafka-Durability wird für jede Partition unabhängig definiert.

Ein Producer, der in mehrere Partitionen schreibt, muss daher darauf warten, dass die richtige Partition seine Bestätigungsanforderungen erfüllt. Fortschritt in einer anderen Partition darf einen nicht zugehörigen Request nicht bestätigen.

Der Simulator verfolgt diesen Zustand jetzt für jede Partition und jedes Topic separat.

### Ein Producer-Reset löscht den Idempotenz-Zustand

Der Broker speichert den Deduplizierungszustand, der mit einem idempotenten Producer verknüpft ist.

Wird ein simulierter Producer entfernt oder zurückgesetzt, muss auch dieser Zustand entfernt werden. Andernfalls könnten die Datensätze eines neu erstellten Producers fälschlicherweise als alte Retries eingestuft werden.

Das Reset-Verhalten löscht jetzt den entsprechenden Zustand auf Broker-Seite.

### Zurückspulen stellt den Retry-Zustand wieder her

Szenarien lassen sich Schritt für Schritt vor- und zurückspulen.

Das Zurückspulen rekonstruiert jetzt die Retry-Zähler, die während jeder Simulationsrunde verwendet wurden. Der sichtbare Producer-Zustand ist damit konsistent, unabhängig davon, ob sich das Szenario vorwärts oder rückwärts bewegt.

## Verbesserungen am Playground

Der Release enthält außerdem mehrere Korrekturen außerhalb des Producer-Modells.

### Rebalancing von Consumer-Groups

Consumer-Groups im Playground erhielten mehrere Korrektheitskorrekturen:

- der Sticky Assignor minimiert jetzt die Bewegung von Partitionen, statt sie von Grund auf neu zuzuweisen,
- ein statisches Mitglied, das länger als `session.timeout.ms` fernbleibt, wird wie jedes andere Mitglied entfernt,
- das Ändern der Partitionsanzahl eines Topics löst jetzt ein ordentliches Rebalancing aus, ohne den Zustand der Mitglieder zu stören,
- Partitionen werden nie einem Mitglied zugewiesen, das nicht mehr aktiv ist.

### Topic-Konfiguration und Compaction

Kafka reduziert die Partitionsanzahl eines Topics nie. Ein Verkleinern würde Daten löschen und die schlüsselbasierte Partitionierung brechen, weshalb `kafka-topics --alter` dies mit einer `InvalidPartitionsException` ablehnt.

Das Playground folgt jetzt derselben Regel. Eine Verringerung der Partitionsanzahl wird mit einem lehrreichen Fehler abgelehnt, statt Partitionen stillschweigend zu verwerfen.

Kompaktierte Topics verhalten sich ebenfalls präziser:

- ein Tombstone bleibt bestehen, bis sein eigenes `delete.retention.ms`-Karenzfenster abläuft,
- ein Datensatz ohne Schlüssel kann nicht in ein kompaktiertes Topic produziert werden,
- mit `compact,delete` räumt die zeitbasierte Retention gealterte Datensätze jetzt unabhängig von der Compaction auf.

### Share-Links bewahren das vollständige Szenario

Das Playground serialisiert seine Aktionen in die URL, damit ein Szenario mit einer anderen Person geteilt werden kann.

Der Codec berücksichtigt jetzt alle Konfigurationsänderungen, einschließlich Aktualisierungen der Partitionsanzahl. Ein Link, der einen Cluster-Typ aus einem späteren Release-Paket anfordert, fällt jetzt auf eine unterstützte Topologie zurück, statt einen unbrauchbaren Cluster darzustellen.

Das Öffnen eines geteilten Links sollte daher genau das Szenario wiederherstellen, das ursprünglich aufgebaut wurde.

### Korrekturen bei der Interaktion

Mehrere kleinere Probleme im Playground wurden ebenfalls behoben:

- Entitäts-Bezeichner kollidieren nicht mehr, nachdem eine Entität entfernt und neu erstellt wurde,
- die Platzierung von Producern funktioniert auf breiteren Broker-Rastern korrekt.

### Security-Header

Die Website sendet jetzt eine Content Security Policy und eine Permissions Policy.

## Warum mit dem Producer beginnen?

Kafka-Garantien werden oft aus der Perspektive des Brokers diskutiert: Replikation, ISR-Mitgliedschaft, High Watermarks und Leader-Failover.

Die von einer Anwendung beobachtete Garantie hängt jedoch auch vom Producer ab.

Welchen Bestätigungsmodus nutzt er? Führt er Retries durch? Ist Idempotenz aktiviert? Wie viele Requests dürfen gleichzeitig in flight sein? Was passiert, wenn sein lokaler Puffer voll wird?

Diese Einstellungen bestimmen, ob ein Schreibvorgang schnell, dauerhaft, geordnet, dupliziert, blockiert oder abgelehnt ist.

Deshalb konzentriert sich das erste größere Szenario-Paket des Kafka Simulators auf den Producer.

Sobald Batching, Bestätigungen, Retries und Idempotenz sichtbar sind, haben spätere Szenarien zu Replikation, Durability und Transaktionen eine klarere Grundlage.

Öffne den [Kafka Simulator](/kafka-simulator/), wähle den Producer-Track und probiere die Ausfallszenarien Schritt für Schritt aus.