In verteilten Umgebungen ist ein Ausfall ein sehr häufiges Szenario, das jederzeit auftreten kann. In einer Kafka-Umgebung kann der Broker abstürzen, ein Netzwerkfehler, ein Fehler bei der Verarbeitung, ein Fehler beim Veröffentlichen von Nachrichten oder ein Fehler beim Konsumieren von Nachrichten usw. Dieses unterschiedliche Szenario führte zu unterschiedlichen Arten von Datenverlust und -duplizierung.
Fehlerszenarien
A (Bestätigung fehlgeschlagen): Der Produzent hat die Nachricht erfolgreich mit einem Wiederholungsversuch> 1 veröffentlicht, konnte jedoch aufgrund eines Fehlers keine Bestätigung erhalten. In diesem Fall versucht der Produzent erneut, dass dieselbe Nachricht ein Duplikat enthält.
B (Erzeugerprozess in Batch-Nachrichten fehlgeschlagen): Der Produzent hat einen Stapel von Nachrichten gesendet, die mit wenigen veröffentlichten Erfolgen fehlgeschlagen sind. In diesem Fall wird der Produzent nach dem Neustart erneut alle Nachrichten aus dem Stapel erneut veröffentlichen, wodurch ein Duplikat in Kafka eingeführt wird.
C (Fire & Forget Failed) Vom Produzenten veröffentlichte Nachricht mit Wiederholung = 0 (Feuer und Vergessen). Wenn ein veröffentlichter Fehler die nächste Nachricht nicht erkennt und sendet, geht die Nachricht verloren.
D (Verbraucher in Batch-Nachricht fehlgeschlagen) Ein Verbraucher empfängt einen Stapel von Nachrichten von Kafka und schreibt ihren Offset manuell fest (enable.auto.commit = false). Wenn der Verbraucher vor der Verpflichtung gegenüber Kafka versagt hat, wird der Verbraucher beim nächsten Mal wieder dieselben Datensätze verwenden, die auf der Verbraucherseite ein Duplikat reproduzieren.
Genau einmalige Semantik
Selbst wenn ein Produzent versucht, eine Nachricht erneut zu senden, führt dies in diesem Fall dazu, dass die Nachricht genau einmal veröffentlicht und vom Verbraucher konsumiert wird.
Um in Kafka eine genau einmalige Semantik zu erreichen, werden weniger als 3 Eigenschaften verwendet
- enable.idempotence = true (Adresse a, b & c)
- MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5 (Der Produzent hat immer eine Anforderung während des Fluges pro Verbindung)
- isolation.level = read_committed (Adresse d)
Idempotent aktivieren (enable.idempotence = true)
Durch die unzulässige Zustellung kann der Hersteller während der Lebensdauer eines einzelnen Herstellers ohne Datenverlust und Bestellung pro Partition genau einmal eine Nachricht an Kafka an eine bestimmte Partition eines Themas schreiben.
"Beachten Sie, dass zum Aktivieren der Idempotenz MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION kleiner oder gleich 5 sein muss, RETRIES_CONFIG größer als 0 und ACKS_CONFIG 'all' sein muss. Wenn diese Werte nicht explizit vom Benutzer festgelegt werden, werden geeignete Werte ausgewählt. Wenn inkompatible Werte sind gesetzt, wird eine ConfigException ausgelöst "
Um Idempotenz zu erreichen, verwendet Kafka eine eindeutige ID, die als Produkt-ID oder PID und Sequenznummer bezeichnet wird, während Nachrichten erstellt werden. Der Produzent erhöht die Sequenznummer für jede veröffentlichte Nachricht, die eine eindeutige PID aufweist. Der Broker vergleicht immer die aktuelle Sequenznummer mit der vorherigen und lehnt ab, wenn die neue nicht +1 größer als die vorherige ist, wodurch Duplikate vermieden werden, und gleichzeitig, wenn mehr als eine größere Show in Nachrichten verloren geht
Im Fehlerszenario vergleicht der Broker die Sequenznummer mit der vorherigen und wenn die Sequenz nicht erhöht wird, lehnt +1 die Nachricht ab.
Transaktion (Isolationsstufe)
Transaktionen geben uns die Möglichkeit, Daten in mehreren Themenpartitionen atomar zu aktualisieren. Alle in einer Transaktion enthaltenen Datensätze werden erfolgreich gespeichert, oder keiner von ihnen wird erfolgreich gespeichert. Auf diese Weise können Sie Ihre Consumer-Offsets zusammen mit den von Ihnen verarbeiteten Daten in derselben Transaktion festschreiben und so eine durchgängige Semantik genau einmal zulassen .
Der Produzent wartet nicht darauf, eine Nachricht an kafka zu schreiben, in der der Produzent beginTransaction, commitTransaction und abortTransaction verwendet (im Fehlerfall). Der Consumer verwendet isolation.level, entweder read_committed oder read_uncommitted
- read_committed: Der Verbraucher liest immer nur festgeschriebene Daten.
- read_uncommitted: Liest alle Nachrichten in versetzter Reihenfolge, ohne darauf zu warten, dass Transaktionen festgeschrieben werden
Wenn ein Verbraucher mit isolation.level = read_committed eine Kontrollnachricht für eine Transaktion erreicht, die nicht abgeschlossen wurde, werden keine weiteren Nachrichten von dieser Partition übermittelt, bis der Produzent die Transaktion festschreibt oder abbricht oder ein Transaktionszeitlimit auftritt. Das Transaktionszeitlimit wird vom Hersteller mithilfe der Konfiguration transaction.timeout.ms (Standard 1 Minute) festgelegt.
Genau einmal bei Produzent & Konsument
In normalem Zustand, wo wir getrennte Produzenten und Konsumenten haben. Der Produzent muss idempotent sein und gleichzeitig die Transaktion verwalten, damit der Konsument Isolation.level verwenden kann, um nur read_committed zu lesen und den gesamten Prozess als atomare Operation auszuführen. Dies garantiert, dass der Produzent immer mit dem Quellsystem synchronisiert wird. Selbst wenn ein Absturz des Produzenten oder eine Transaktion abgebrochen wird, ist dies immer konsistent und veröffentlicht eine Nachricht oder einen Stapel von Nachrichten einmal als Einheit.
Derselbe Verbraucher erhält entweder einmal eine Nachricht oder einen Nachrichtenstapel als Einheit.
In Exactly-Once wird der semantische Produzent zusammen mit dem Verbraucher als atomare Operation erscheinen, die als eine Einheit arbeiten wird. Entweder veröffentlichen und einmal verbrauchen oder abgebrochen werden.
Genau einmal im Kafka Stream
Kafka Stream verwendet Nachrichten aus Thema A, verarbeitet und veröffentlicht Nachrichten in Thema B und verwendet nach der Veröffentlichung Commit (Commit wird meistens unter Deckung ausgeführt), um alle Statusspeicherdaten auf die Festplatte zu leeren.
Genau einmal in Kafka Stream gibt es ein Lese-Prozess-Schreibmuster, das garantiert, dass diese Operation als atomare Operation behandelt wird. Da Kafka Stream Hersteller, Verbraucher und Transaktion zusammen versorgt, bietet Kafka Stream eine spezielle Parameterverarbeitung. Garantie, die genau einmal oder mindestens einmal verfügbar sein kann und es dem Leben leicht macht, nicht alle Parameter separat zu behandeln.
Kafka Streams aktualisiert Verbraucher-Offsets, lokale State Stores, State Store Changelog-Themen und Produktion atomar, um Themen zusammen auszugeben. Wenn einer dieser Schritte fehlschlägt, werden alle Änderungen rückgängig gemacht.
process.guarantee: sure_once liefert automatisch die folgenden Parameter, die Sie nicht explizit festlegen müssen
- isolation.level = read_committed
- enable.idempotence = true
- MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION = 5