Delivery Semantics (At Most Once, At Least Once, Exactly Once)
Zustellung und fachliche Ausführung unterscheiden
Die Idee und ihr Nutzen
Der Zahlungsdienst einer Versicherung erhält von einer Nachrichtenplattform den Auftrag, für Schaden 4711 an einen Kunden 1.200 Euro auszuzahlen. Der Zahlungsdienst gibt die Zahlung an einen externen Zahlungsanbieter weiter, stürzt aber ab, bevor er der Nachrichtenplattform den Empfang bestätigt. Die Nachrichtenplattform weiß nicht, ob der Auftrag erledigt wurde, und stellt ihn deshalb ein zweites Mal zu. Der Zahlungsdienst muss nun verhindern, dass der Kunde 2.400 Euro erhält. Was die Nachrichtenplattform zusagt, etwa dass sie jeden Auftrag mindestens einmal zustellt, betrifft nur die Zustellung einer Nachricht, nicht die Ausführung der Zahlung. Welche Zusage für jeden Schritt gilt, muss das Team, das den Zahlungsdienst baut, deshalb ausdrücklich klären. Für die Zustellung gibt es drei Zusagen mit englischen Namen: At Most Once (höchstens einmal), At Least Once (mindestens einmal) und Exactly Once (genau einmal). Zusammen heißen sie Delivery Semantics, wörtlich „Bedeutung der Zustellung“, weil sie festlegen, was „zugestellt“ bei einer Nachrichtenplattform heißt.
Wie funktioniert es?
Die Nachrichtenplattform der Versicherung arbeitet mit der Zusage „mindestens einmal“. Die Nachrichtenplattform stellt dem Zahlungsdienst den Auftrag „Zahle 1.200 Euro für Schaden 4711“ mit der Auftragskennung „zahlung-4711-01“ zu und bewahrt den Auftrag weiter auf. Der Zahlungsdienst schickt Auftrag und Kennung an den Zahlungsanbieter. Der Zahlungsanbieter überweist dem Kunden 1.200 Euro und merkt sich die Kennung. Bevor der Zahlungsdienst der Nachrichtenplattform den Empfang bestätigen kann, stürzt der Zahlungsdienst ab. Nach dem Neustart des Zahlungsdienstes stellt die Nachrichtenplattform denselben Auftrag erneut zu, weil die Bestätigung fehlt. Der Zahlungsdienst schickt den Auftrag mit derselben Kennung „zahlung-4711-01“ noch einmal an den Zahlungsanbieter. Der Zahlungsanbieter erkennt die Kennung, führt keine zweite Überweisung aus und meldet „bereits ausgeführt“. Erst jetzt bestätigt der Zahlungsdienst der Nachrichtenplattform den Auftrag. Der Kunde erhält 1.200 Euro, nicht 2.400 Euro.
Eine Nachrichtenplattform ist ein eigenes Programm, das Nachrichten annimmt, aufbewahrt und an Empfänger zustellt. Hat der Empfänger eine Nachricht verarbeitet, schickt er der Nachrichtenplattform eine Bestätigung. Erst an der Bestätigung erkennt die Nachrichtenplattform, dass sie die Nachricht nicht mehr zustellen muss. Der Zahlungsanbieter ist ein System außerhalb der Versicherung, das die eigentliche Überweisung ausführt. Das Team betreibt den Zahlungsanbieter nicht selbst und kann ihn nicht ändern.
Auf dem Weg vom Absender über die Nachrichtenplattform zum Empfänger kann einiges schiefgehen. Die Nachricht kommt nicht an. Der Empfänger stürzt während der Verarbeitung ab. Oder die Bestätigung des Empfängers geht auf dem Rückweg verloren. In den beiden letzten Fällen weiß die Nachrichtenplattform nicht, ob der Auftrag angekommen und erledigt ist. Stellt die Nachrichtenplattform den Auftrag erneut zu, wird er vielleicht doppelt ausgeführt; stellt sie ihn nicht erneut zu, fehlt er vielleicht. Bei einer Zahlung schaden beide Fehler: Eine verlorene Zahlung verärgert den Kunden, eine doppelte Zahlung kostet die Versicherung Geld und bringt Aufwand für die Rückforderung. Wer nicht genau weiß, was die eingesetzte Nachrichtenplattform zusagt, baut womöglich ein System, das bei Störungen Zahlungen verliert oder verdoppelt.
Nachrichtenplattformen machen eine von drei Zusagen:
- At Most Once, höchstens einmal: Die Nachrichtenplattform stellt jede Nachricht nur einmal zu und versucht es bei einem Fehler nicht erneut. Eine Nachricht kommt also nie doppelt an, kann aber verloren gehen.
- At Least Once, mindestens einmal: Die Nachrichtenplattform bewahrt jede Nachricht auf, bis der Empfänger sie bestätigt, und stellt sie erneut zu, wenn die Bestätigung fehlt. Die Nachricht geht nicht verloren, solange die Nachrichtenplattform sie sicher aufbewahrt und irgendwann ein Empfänger erreichbar ist. Derselbe Auftrag kann aber mehrfach ankommen.
- Exactly Once, genau einmal: Manche Nachrichtenplattformen sagen zu, dass eine Nachricht genau einmal verarbeitet wird, solange Lesen, Verarbeiten und Speichern des Ergebnisses innerhalb der Nachrichtenplattform geschehen. Diese Nachrichtenplattformen speichern dafür in einem einzigen Schritt, welche Nachricht gelesen wurde, was die Verarbeitung ergeben hat und dass die Nachricht bestätigt ist. Entweder wird alles gespeichert oder nichts. Die Zusage gilt deshalb nur für das, was die Nachrichtenplattform selbst speichert. Ein Aufruf beim Zahlungsanbieter geschieht außerhalb der Nachrichtenplattform und ist durch die Zusage nicht geschützt.
Für den Zahlungsdienst wählt das Team „mindestens einmal“ und gibt jedem Auftrag eine eindeutige Auftragskennung mit, die der Zahlungsanbieter wiedererkennt. Die Zusage der Nachrichtenplattform verhindert dann, dass ein Auftrag verloren geht. Der Zahlungsanbieter verhindert anhand der Kennung, dass eine zweite Zustellung eine zweite Überweisung auslöst. Es genügt auch, wenn der Zahlungsanbieter zuverlässig Auskunft gibt, ob ein Auftrag schon ausgeführt wurde. Ein Vermerk in der eigenen Datenbank des Zahlungsdienstes genügt dagegen nicht, denn der Absturz kann genau zwischen der Überweisung und diesem Vermerk passieren.
Für den Zahlungsdienst kommt es außerdem darauf an, wann er bestätigt. Bestätigt der Zahlungsdienst den Auftrag zuerst und stürzt vor dem Weitergeben der Zahlung ab, ist der Auftrag verloren. Gibt der Zahlungsdienst die Zahlung zuerst weiter und stürzt vor der Bestätigung ab, kommt der Auftrag ein zweites Mal. Bei Zahlungen wählt man meist die zweite Reihenfolge. Der Zahlungsanbieter erkennt die zweite Zustellung dann an der Auftragskennung und führt keine zweite Zahlung aus.
Mindestens einmal zugestellt, nur einmal ausgezahlt
Wann ist es sinnvoll und wann nicht?
Wann welche Zusage passt
- „Höchstens einmal“ genügt für Daten, deren Verlust harmlos ist. Beispiele sind häufige Messwerte und Standortangaben, die bald ohnehin durch neue ersetzt werden. Messwerte zur Auslastung eines Servers werden jede Sekunde neu gesendet, und wenn einer von tausend Werten fehlt, ändert das nichts an der Auswertung. Für solche Messwerte spart „höchstens einmal“ Bestätigungen und Speicherplatz.
- „Mindestens einmal“ mit einer Auftragskennung eignet sich für Aufträge, die weder verloren gehen noch doppelt ausgeführt werden dürfen. Ein Beispiel sind Zahlungsaufträge. Voraussetzung ist, dass der Empfänger oder das ausführende System doppelte Zustellungen sicher erkennt. Bei der Auszahlung für Schaden 4711 erkennt der Zahlungsanbieter sie an der Kennung. Ohne Auftragskennung würde der Zahlungsanbieter nach der zweiten Zustellung ein zweites Mal überweisen, und der Kunde erhielte 2.400 Euro. Außerdem muss die Nachrichtenplattform die Nachrichten dauerhaft aufbewahren.
- „Genau einmal“ eignet sich, wenn die ganze Verarbeitung innerhalb der Nachrichtenplattform bleibt. Ein Beispiel ist ein Programm, das Nachrichten aus der Nachrichtenplattform liest, umrechnet und das Ergebnis wieder in die Nachrichtenplattform schreibt. Ohne diese Zusage müsste das Programm nach einem Absturz selbst herausfinden, welche Nachrichten es schon umgerechnet hat, sonst stehen manche Ergebnisse doppelt in der Nachrichtenplattform.
Wann eine Zusage nicht passt
- „Höchstens einmal“ ist ungeeignet für Aufträge, die nicht verloren gehen dürfen. Ein Beispiel ist die Auszahlung für Schaden 4711. Stürzt der Zahlungsdienst ab, bevor er die Zahlung an den Zahlungsanbieter weitergibt, stellt die Nachrichtenplattform den Auftrag nicht erneut zu, und der Kunde erhält nichts. Deshalb wählt das Team „mindestens einmal“ mit einer Auftragskennung. Die Nachrichtenplattform stellt den Auftrag nach einem Absturz des Zahlungsdienstes erneut zu, und der Kunde erhält sein Geld trotzdem.
- „Genau einmal“ reicht nicht aus, sobald ein externes System wie der Zahlungsanbieter beteiligt ist. Die Zusage gilt nur für das, was die Nachrichtenplattform selbst speichert, und nach einem Absturz des Zahlungsdienstes kann der Zahlungsanbieter denselben Auftrag ein zweites Mal erhalten. Deshalb schickt der Zahlungsdienst jeden Auftrag mit seiner Auftragskennung an den Zahlungsanbieter, und der Zahlungsanbieter führt einen Auftrag mit bekannter Kennung kein zweites Mal aus.
- „Mindestens einmal“ ohne Erkennung doppelter Aufträge ist ungeeignet für alles, was Geld bewegt oder Datensätze anlegt. Nach jedem Absturz des Zahlungsdienstes vor der Bestätigung überweist der Zahlungsanbieter ein zweites Mal. Ruft der Empfänger ein externes System wie den Zahlungsanbieter auf, erkennt dieses System doppelte Aufträge an der Auftragskennung. Ändert die Verarbeitung nur Daten in der eigenen Datenbank des Empfängers, hilft das Inbox Pattern. Der Empfänger erkennt doppelte Zustellungen dann selbst an einer Tabelle bereits verarbeiteter Nachrichten, ohne dass ein anderes System mitwirken muss. Anders als beim Aufruf des Zahlungsanbieters genügt dieser eigene Vermerk hier, weil der Empfänger die Änderung und den Vermerk in einem Schritt in derselben Datenbank speichert.
- Der Zahlungsanbieter prüft keine Kennung und gibt keine Auskunft über bereits ausgeführte Aufträge. Dann hilft auch die Auftragskennung nicht, und es bleibt nur ein nachträglicher Abgleich. Das Team behält „mindestens einmal“, damit kein Auftrag verloren geht. Der Zahlungsdienst vergleicht seine Aufträge regelmäßig mit den Ausführungsmeldungen des Zahlungsanbieters, und die Versicherung fordert Doppelzahlungen zurück. Der Abgleich erkennt Fehler erst, wenn das Geld schon überwiesen ist.
Nachteile und typische Fehler
„Mindestens einmal“ und „genau einmal“ machen die Nachrichtenplattform langsamer als „höchstens einmal“, weil sie jede Nachricht speichern und auf Bestätigungen warten muss. Der Schutz vor doppelten Zahlungen hängt vom Zahlungsanbieter ab, den das Team nicht ändern kann. Ändert der Zahlungsanbieter sein Verhalten bei bekannten Kennungen oder wechselt die Versicherung den Zahlungsanbieter, muss das Team erneut prüfen, ob doppelte Aufträge erkannt werden. Das Team muss für jede Nachrichtenart festhalten, welche Zusage es braucht, und bei jeder Nachrichtenplattform nachlesen, für welchen Teil der Verarbeitung deren Zusage gilt. „Exactly Once“ in einer Produktbeschreibung verspricht oft nur, dass die Nachrichtenplattform selbst nichts doppelt speichert, nicht dass ein Aufruf beim Zahlungsanbieter nur einmal geschieht.
Typische Fehler und woran man sie erkennt:
- Überschätzte Zusage: Das Team verlässt sich auf „Exactly Once“ der Nachrichtenplattform und übersieht, dass der Aufruf beim Zahlungsanbieter nicht dazugehört. Der Zahlungsdienst schickt Aufträge deshalb ohne Auftragskennung an den Zahlungsanbieter. Stürzt der Zahlungsdienst nach der Überweisung ab, stellt die Nachrichtenplattform den Auftrag erneut zu, und der Zahlungsanbieter überweist ein zweites Mal. Erkennbar ist das an doppelten Überweisungen nach einem Absturz des Zahlungsdienstes, obwohl die Nachrichtenplattform keine doppelte Verarbeitung meldet.
- Keine Erkennung doppelter Aufträge: Die Nachrichtenplattform stellt „mindestens einmal“ zu, aber weder der Zahlungsdienst noch der Zahlungsanbieter prüft die Kennung. Nach einem Absturz des Zahlungsdienstes stellt die Nachrichtenplattform den Auftrag erneut zu, und der Zahlungsanbieter überweist ein zweites Mal. Erkennbar ist das an zwei Überweisungen mit gleichem Betrag für denselben Schaden kurz nacheinander.
- Zu frühe Bestätigung: Der Zahlungsdienst bestätigt den Auftrag zuerst. Danach stürzt der Zahlungsdienst ab, bevor er die Zahlung an den Zahlungsanbieter weitergibt. Die Nachrichtenplattform stellt den bestätigten Auftrag nicht erneut zu. Erkennbar ist das an Schäden, für die eine Auszahlung beauftragt, aber beim Zahlungsanbieter nie ausgeführt wurde.
- Vermerk nur in der eigenen Datenbank: Der Zahlungsdienst notiert ausgeführte Zahlungen nur in seiner eigenen Datenbank und schickt Aufträge ohne Kennung an den Zahlungsanbieter. Nach einem Absturz zwischen Überweisung und Vermerk findet der Zahlungsdienst bei der zweiten Zustellung keinen Vermerk. Der Zahlungsdienst schickt den Auftrag erneut, und der Zahlungsanbieter überweist ein zweites Mal. Erkennbar ist das an Doppelzahlungen, die genau mit Abstürzen des Zahlungsdienstes zusammenfallen.
- Flüchtige Aufbewahrung: Die Nachrichtenplattform hält Nachrichten nur im Arbeitsspeicher, und bei ihrem eigenen Neustart gehen unbestätigte Aufträge verloren. Erkennbar ist das an fehlenden Aufträgen nach einer Wartung oder einem Absturz der Nachrichtenplattform.
Weiterführend
Verwandte Ansätze
- Idempotency: beschreibt, wie ein Vorgang so gebaut wird, dass eine Wiederholung keine zusätzliche Wirkung hat, etwa über eine Auftragskennung.
- Outbox Pattern: speichert beim Absender jede Nachricht zusammen mit den Daten in dessen Datenbank, sodass keine Nachricht verloren geht.
- Messaging: beschreibt die Nachrichtenplattformen, deren Zusagen auf dieser Seite unterschieden werden.
Werkzeuge und Umsetzungen
- Apache Kafka: bietet Transaktionen, also Schreibvorgänge, die nur gemeinsam oder gar nicht gelten. Damit speichert eine Verarbeitung, die Nachrichten aus Kafka liest und nach Kafka schreibt, Ergebnis und Lesefortschritt gemeinsam. Aufrufe anderer Systeme sind davon nicht erfasst.
- RabbitMQ: unterstützt Bestätigungen beim Absenden und beim Verarbeiten. Für eine verlässliche Zustellung müssen zusätzlich Warteschlangen und wichtige Nachrichten dauerhaft gespeichert werden.
- Apache Flink: kann seinen eigenen Verarbeitungsstand nach einem Absturz so wiederherstellen, dass keine Nachricht doppelt oder gar nicht gezählt ist. Ob Ergebnisse in externen Systemen genau einmal ankommen, hängt davon ab, wie diese Systeme angebunden sind.
- NATS JetStream: speichert Nachrichten in NATS dauerhaft und erkennt innerhalb eines einstellbaren Zeitfensters Nachrichten, die mit derselben Kennung erneut abgeschickt wurden.
Quellen
- RabbitMQ: Reliability Guide: beschreibt Bestätigungen, dauerhafte Speicherung und die Grenzen dessen, was eine Nachrichtenplattform zusagen kann.
- Apache Kafka: Design, Message Delivery Semantics: beschreibt die drei Zusagen, wie die Reihenfolge von Verarbeiten und Speichern des Lesefortschritts über „höchstens einmal“ oder „mindestens einmal“ entscheidet, und dass „genau einmal“ bei anderen Zielsystemen deren Mitwirkung voraussetzt.