Warum Nachrichten doppelt ankommen
At-least-once heißt, dass eine Nachricht mindestens einmal ankommt, manchmal aber doppelt. Ein Konsument, der damit sicher umgeht, verarbeitet jede Nachricht so, dass eine Wiederholung nichts ändert: Er ist idempotent.
Ein Zahlungsdienst darf eine Zahlung nie zweimal buchen, auch wenn sein Konsument zwischendurch abstürzt und neu startet.
Am Ende dieser Lektion
Notiz
Ich kann einen Konsumenten entwerfen, der Wiederholungen übersteht.
Schlüsselwörter
| Begriff | Was er bedeutet |
|---|---|
| At-least-once | jede Nachricht kommt mindestens einmal an, vielleicht öfter |
| At-most-once | jede Nachricht kommt höchstens einmal an, vielleicht nie |
| Idempotent | zweimal ausgeführt wirkt es wie einmal |
| Offset | die Platznummer einer Nachricht in ihrer Partition |
| Bestätigung | der Konsument speichert, bis wohin er gelesen hat (Commit) |
| Duplikat | eine Nachricht, die schon einmal verarbeitet wurde |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Drei Zusagen für die Zustellung einer Nachricht
Bei At-most-once wird eine Nachricht höchstens einmal zugestellt. Geht sie verloren, ist sie weg. Bei At-least-once kommt sie mindestens einmal an. Geht eine Bestätigung verloren, kommt sie erneut.
Ein Netz kann nie sicher sagen, ob eine Nachricht ankam. Darum nutzt man meist At-least-once und fängt die Doppelten in der Verarbeitung ab.
Beispiel: wann der Konsument bestätigt
| Reihenfolge | Stürzt er ab, dann … | Zusage |
|---|---|---|
| Erst bestätigen, dann verarbeiten | ist die Nachricht verloren | At-most-once |
| Erst verarbeiten, dann bestätigen | wird sie nach dem Neustart wiederholt | At-least-once |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein Absturz vor der Bestätigung
# Ein Konsument liest 3 Nachrichten. Er stürzt nach der zweiten ab, bevor er den Offset speichert.
nachrichten = ["zahlung1", "zahlung2", "zahlung3"]
gespeicherter_offset = 0
for nummer in range(2):
print("Verarbeite", nachrichten[nummer])
# Absturz: gespeicherter_offset wurde nie erhöht. Nach dem Neustart:
for nummer in range(gespeicherter_offset, 3):
print("Neustart verarbeitet", nachrichten[nummer])
# Rücken Sie gespeicherter_offset nach jeder Nachricht vor und beobachten Sie die Doppelten.
Idempotent heißt: zweimal wirkt wie einmal
Eine Verarbeitung ist idempotent, wenn eine Wiederholung nichts ändert. „Setze den Kontostand auf 80“ ist idempotent. „Buche 20 Euro ab“ ist es nicht.
Der einfachste Weg: Jede Nachricht trägt eine eindeutige Nummer. Der Konsument merkt sich die Nummern, die er schon verarbeitet hat, und überspringt jede weitere Nachricht mit derselben.
Doppelte Nachrichten überspringen
# Eine Verarbeitung, die sich gesehene Nummern merkt, hält Doppelte auf.
eingang = ["z1", "z2", "z1", "z3", "z2"]
gesehen = {}
summe = 0
for nummer in eingang:
if nummer in gesehen:
print(nummer, "ist ein Duplikat, wird übersprungen")
else:
gesehen[nummer] = True
summe = summe + 10
print("Summe:", summe, "Euro")
# Entfernen Sie die Prüfung und vergleichen Sie die Summe.
Ein Topic mit einer Partition anlegen
curl -s -X POST -H "Content-Type: application/json" -d '{"name":"zahlungen","partitions":1,"replicationFactor":1,"configs":{}}' http://kafka-ui:8080/api/clusters/lab/topics -o /dev/null -w "%{http_code}\n"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Dieselbe Zahlung senden
curl -s -X POST -H "Content-Type: application/json" -d '{"partition":0,"key":"zahlung7","value":"bezahlt","headers":{},"keySerde":"String","valueSerde":"String"}' http://kafka-ui:8080/api/clusters/lab/topics/zahlungen/messages -w "%{http_code}\n"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Dieselbe Zahlung noch einmal senden
curl -s -X POST -H "Content-Type: application/json" -d '{"partition":0,"key":"zahlung7","value":"bezahlt","headers":{},"keySerde":"String","valueSerde":"String"}' http://kafka-ui:8080/api/clusters/lab/topics/zahlungen/messages -w "%{http_code}\n"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Offsets der Partition ansehen
curl -s http://kafka-ui:8080/api/clusters/lab/topics/zahlungen | grep -o '"partition":[0-9]*\|"offsetMax":[0-9]*'Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Beide Kopien im Log lesen
curl -s -N "http://kafka-ui:8080/api/clusters/lab/topics/zahlungen/messages/v2?seekType=BEGINNING&partitions=0&limit=10" | grep -o '"partition":[0-9]*,"offset":[0-9]*\|"value":"[a-z]*"'Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Ein häufiger Fehler
Warnung
Viele denken, ein gutes System liefere jede Nachricht genau einmal. Ein Netz kann das nie sicher zusagen, denn eine Bestätigung kann verloren gehen. Verlassen Sie sich nicht darauf, sondern machen Sie die Verarbeitung idempotent.