Kafka-Consumer Sollten Idempotent Sein, Auch Wenn Sie 'Genau Einmal' Hören_
Die Genau-einmal Semantik in Kafka ist enger als viele Teams annehmen. Idempotenz auf der Verbraucherseite ist weiterhin das sicherere Design für Nebeneffekte.
Wenn ein Kafka-Consumer einen Nebeneffekt auslöst, gehen Sie davon aus, dass Duplikate möglich sind, bis Sie das Gegenteil bewiesen haben.
Das ist die sicherere Standardvorgehensweise.
Kafka hat Genau-einmal-Funktionen, aber Ingenieure interpretieren oft über, was diese Garantien abdecken. Sie helfen viel im eigenen Verarbeitungsmodell von Kafka. Sie machen jedoch nicht magisch jeden nachgelagerten Datenbankschreibvorgang oder externen API-Aufruf duplikatfrei.
Das Verbraucherproblem
Das riskante Muster sieht so aus:
Nachricht konsumieren
Datenbank aktualisieren
Fortschritt bestätigen
Wenn der Dienst zwischen den Schritten abstürzt, kann ein Replay stattfinden.
Das ist nicht Kafka, das kaputt ist. Es ist normales Verhalten verteilter Systeme unter Fehlerbedingungen.
Verwenden Sie einen Idempotenzschlüssel
Jedes Ereignis, das einen Nebeneffekt auslösen kann, sollte einen stabilen Identifikator tragen:
Machen Sie dann den Nebeneffekt davon abhängig, ob dieses Ereignis bereits angewendet wurde.
Lassen Sie die Datenbank es durchsetzen
Ein gängiger und zuverlässiger Ansatz ist ein eindeutiger Schlüssel:
CREATE TABLE processed_events ( event_id text PRIMARY KEY, processed_at timestamptz NOT NULL DEFAULT now());
Verarbeiten Sie dann innerhalb einer Transaktion:
BEGIN;INSERT INTO processed_events (event_id)VALUES ($1);UPDATE walletsSET balance = balance - $2WHERE id = $3;COMMIT;
Wenn dasselbe Ereignis erneut abgespielt wird, schlägt das Einfügen am eindeutigen Schlüssel fehl, und der Verbraucher kann es als bereits bearbeitet behandeln.
Das ist oft einfacher und vertrauenswürdiger als ad-hoc Deduplication im Speicher.
Das nützliche mentale Modell
Zielen Sie nicht darauf ab, dass "Duplikate niemals passieren."
Zielen Sie darauf ab, dass "Duplikate den finalen Zustand nicht ändern."