Results 1 to 2 of 2

Event sourcing: Kontobuchung

  1. #1 Reply With Quote
    Ritter Delta 38's Avatar
    Join Date
    Nov 2008
    Location
    Bremen
    Posts
    1,251
    Ich versuche mich gerade in das Konzept hinter Event Sourcing/CQRS einzuarbeiten. Auch wenn ich die Vorteile sehr schätze, komme ich doch an einem Punkt nicht weiter:

    Ich habe ein Programm, welches Geld zwischen verschiedenen Konten umbuchen soll.
    1. Die Umbuchung soll nur stattfinden, wenn genug Geld auf dem Absenderkonto ist.
    2. Was passiert, wenn ich eine Umbuchung auf Grundlage eines veralteten Read-Models starte? Eines der beteiligten Konten könnte ja zwischendrin gelöscht worden sein.

    Das Umbuchen wird über ein Kommando an den CQRS Broker gestartet. Aggregates können sich bei dem Broker registrieren, um neue Kommandos zu empfangen. Der Broker sendet dann einfach das Umbuchen-Kommando an alle Abonnenten. Was passiert, wenn das Aggregate nicht mehr existiert, oder sich gar nicht registriert hat? Für die Umbuchung müssen alle beteiligten Aggregates das Kommando ausführen. Soll der Broker per Timeout warten, bis er alle Events (EinzahlungAbgeschlossen und AuszahlungAbgeschlossen) erhält? Das erscheint mir irgendwie nicht sinnvoll.

    Gruß,
    Delta
    Delta 38 is offline

  2. #2 Reply With Quote
    Forschungsreisender  jabu's Avatar
    Join Date
    Jul 2011
    Posts
    4,732
    Ich bin kein Fachmann auf dem Gebiet solcher Architekturen (kann aber grob nachvollziehen, was gemeint ist, wobei jedoch die gegebenen Infos m.E. zu spärlich sind), weswegen das nur als Anregung zu verstehen ist:

    Ich vermute, dass die Probleme tiefer liegen, nämlich bei der Abstraktion von "Kontoführung", was nicht ganz trivial ist. So unterscheidet, mit gutem Grund, meine Bank zwischen Buchung und Wertstellung sowie zwischen tatsächlichem Guthaben (existiert, weil das Konto laufend geführt ist, vermutlich nur zum Abrechnungszeitpunkt und nur, wenn das Konto rechtzeitig eingefroren wurde, z.B. wegen Auflösung) und verfügbarem Guthaben (sorry, dass ich bei den letzten beiden Begriffen die Fachterminologie unberücksichtigt lasse, bin kein Banker). Überweisungen werden als Auftrag angenommen und nicht direkt ausgeführt.

    Wenn Beträge vom Konto abgehen sollen, wie bei einem Überweisungsauftrag, dann wird der Betrag, der abgehen, soll, sofort vom verfügbaren Guthaben abgezogen, damit das Konto nicht so leicht unberechtigt überzogen werden kann und damit man auch selber einen besseren Überblick hat. Tatsächlich ist das Geld noch gar nicht weg, denn es wurde lediglich ein Überweisungsauftrag erteilt. Es wird mindestens auf einem internen Gegenkonto der Bank verbucht, bis die Transaktion tatsächlich abgeschlossen ist. Bei meiner Bank ist es üblich, dass die Wertstellung bei Abgängen anscheinend sofort erfolgt, sodass mein Guthaben sofort oder fast sofort gemindert ist. Es ist aber vielleicht nicht hundertprozentig sicher, dass keine Lücke existiert, sodass vielleicht ein fast gleichzeitiger anderer Abgang das verfügbare Limit sprengen könnte.

    Wenn man das verhindern will (z.B. für die Regel "Konto darf nicht ins Minus rutschen"), dann muss die Wertstellung atomar mit dem Überweisungsauftrag erfolgen. Eine Bank muss das nicht tun, da sie immer über genügend Geld verfügt und kaum Mühe hat, ihre Forderungen geltend zu machen und weil die eingeräumten Limits gegenüber dem Kapital der Bank ein Witz sind. Bei kleinen Geschäftsleuten droht jedoch schon wahrscheinlicher ein Verlust (u.U. bis in die Insolvenz), weswegen es im Regelfall niemals zu solchen Überschneidungen kommen darf! Für Folgen daraus wäre der Entwickler bzw. Anbieter der Software wohl haftbar (es sei denn, es ist ausdrücklich so bestellt worden).

    Daraus ergibt sich, dass der Überweisungsauftrag zusammen mit der Aktualisierung des verfügbaren Guthabens atomar (unteilbar) erfolgen muss (nicht aber mit der Ausführung der Buchungen!). Mit einem anwachsenden Stapel wäre entweder unerlaubtes Überziehen oder ewiges Warten (bis alles darunter abgearbeitet ist) eine ganz normale Folge (die man erst bemerkt, wenn es zu spät ist). Vordrängeln führt m.E. zu noch größeren Problemen.

    Es ist also für das betreffende Konto ein Lock erforderlich, um andere Manipulationen zu unterbinden, bis der Überweisungsauftrag (z.B. mit Gegenkonto für Rückabwickelbarkeit; nicht: die Buchung(en)!) erfolgt und die Aktualisierung der verfügbaren Guthabens abgeschlossen ist. Damit ist es möglich, zu überprüfen, ob der Vorgang a) als solcher einer eingeräumten Richtlinie entspricht und b) die Richtlinie nicht verletzt. Nur dann wird Erfolg zurückgemeldet. Bei Misserfolg kann ein Fehlertext gespeichert werden, den der Client dann anfordern kann. Der muss aber zur Transaktion passen, nicht dass der beim nächsten Mal ausgegeben wird (abgesehen von, falls gewünscht, zusätzlich hinterlegten Nachrichten, z.B. in Form eines Protokolls).

    Wir erhalten also etwa mindestens diese, jeweils für sich, atomaren Phasen:
    1. Abfrage des Kontostandes (zum Zeitpunkt der Abfrage) -> unproblematisch (bis auf hoffentlich selbstverständliches atomares Read), da für Transaktion irrelevant
    2. Anweisen des Auftrags für eine Einzelüberweisung (in der Geschäftslogik atomar bis Erfolg oder Misserfolg)
    3. Abfrage des Kontostandes (zum Zeitpunkt der Abfrage) -> unproblematisch (bis auf hoffentlich selbstverständliches atomares Read), da für Transaktion irrelevant

    Der beim Client angezeigte Kontostand legitimiert zu gar nichts, und es wäre schlimm, wenn er es täte. Die Hoheit muss bei der Geschäftslogik verbleiben. Nur sie kann die Regeln kontrollieren und durchsetzen. Und derjenige extern motivierte Vorgang, welcher für das betreffene Konto zuerst kommt, mahlt zuerst, alle anderen extern motivierten Vorgänge für dieses Konto müssen warten. Und gegen Spam (die Queue wird immer länger, was das System aus dem Tritt bringen könnte (und deswegen irgendwann wird)) verhindert man, dass sich für dasselbe Konto mehrfach angemeldet wird, wozu (weil Abmelden niemals garantiert sein kann) ein Timeout vonseiten der Geschäftslogik nötig ist. Dann meldet der Client eben, dass der Vorgang zur Zeit nicht möglich ist, man möge es später erneut versuchen. Dieses folgt der Idee eines geringsten anzunehmenden Schadens. Das hilft natürlich nur auf der Ebene autorisierter Sitzungen.

    Erst nach dem Anweisen des Auftrags für die Einzelüberweisung wird die Überweisung ausgeführt. Der Abgang erfolgte von vornherein unter Vorbehalt, sodass der Betrag bloß markiert oder auf einem Gegenkonto der "Bank" gesichert wurde. Lediglich das verfügbare Guthaben wurde gemindert, wenn alles richtig implementiert ist. Falls irgendeine Komponente abstürzt, wozu auch Stromausfall gehört, muss immer ein nahtloses Weiteroperieren auf der Grundlage absolut gültiger Daten möglich sein, weswegen die Reihenfolgen, was synchron sowie was atomar sein muss, bis ins letzte Detail ausgeklügelt sein muss. Andernfalls bräuchtest du wohl eine Schaar an billigen und dennoch absolut zuverlässigen Hilskräften sowie die eine oder andere eidesstattliche Erklärung seitens Kunden. Ein automatisches Failure Recovery muss immer möglich sein, wenn es nicht nur eine Handvoll Kunden gibt, sonst bekämest du die Pest an den Hals. Und korrekt muss der Kram immer sein, ganz egal, in welcher Nanosekunde der Strom weg ist oder eine Komponente abraucht. Dabei lässt sich natürlich nicht verhindern, dass in solchen Situationen Falsches geschrieben wird, aber es lässt sich (bis auf Inkonsistenzen in den Sicherungen, wobei die erkennbar gemacht und Alarm auslösen müssen) gewährleisten, dass über die Historie die Fehler gefixt werden können. Ich würde auch jede Transaktion unter Vorbehalt stellen und sie erst nach nachträglicher Prüfung freigeben und einen Alarm auslösen lassen (mit automatischer Kontosperrung), falls sich im gespeicherten Ergebnis Differenzen ergeben (was immer eine Katastrophe andeutet). Dann müsste ein Mensch sich das angucken. Bits können kippen, auch ohne Programmfehler, ist leider ganz normal. Wahrscheinlicher sind bei komplexen Systemen zeitabhängige Glitches, die beim Test nicht auffallen.

    Wann die Buchung tatsächlich erfolgt (müsste jedoch ein Zeitlimit geben, falls nicht deterministisch durchgedrückt) und ob sie klappt, ist egal. Es ist also völlig unnötig, darauf zu warten. Meine Bank führt Überweisungen nur gegen 0.00 Uhr aus. Wenn das bei dir innerhalb weniger Sekunden erfolgt, so ist das schon komfortabel und bei Minuten vielleicht noch kein Problem. Der Client sieht den Abgang (und er muss nicht lange warten, weil der Rest entkoppelt ist) und ist zufrieden. Sollte es irgendwelche Probleme mit dem Empfängerkonto geben, so schlägt der Vorgang fehl. Die Gründe dafür geht den Sender nichts an. Das Guthaben, das nur unter Vorbehalt abgezogen wurde, ist ja noch bei der "Bank", entweder unsichtbar auf dem Senderkonto oder auf einem Gegenkonto auf der Bank oder unter Einbeziehung beider Mechanismen eben hier und dort.

    Keine Buchung ohne Beleg, kein Konto ohne Gegenkonto, das ist schon für Kassensturzfähigkeit sowie für eine ordnungsgemäße Buchführung nötig und meistens auch gesetzlich vorgeschrieben (sonst darf das Finanzamt schätzen, was zu deinen Ungunsten ausgehen wird). Die Software muss dafür sorgen, dass im Versagensfall volle Rekonstruierbarkeit besteht. Das ist ein nicht triviales Unterfangen (Thema ist auch erst angekratzt), auf das ich jetzt echt keinen Bock hätte (weswegen solche Software, wenn sie denn funktioniert (sieht man erst, wenn es zu spät ist), nicht billig ist)...

    Das Event Sourcing mag diesen Forderungen bereits implizit entgegenkommen, doch dürfte es von vielen Implementierungsdetails abhängen, ob sie tatsächlich vollumfänglich erfüllt sind!

    Ein Vermerk zur Vorsicht: Ich bin weder auf diesem Gebiet noch auf dem von Steuern noch auf dem des Rechts fachkundig, weswegen das hier nur als Denkanstoß zu verstehen ist, weswegen mit Fehlern sowie mit Auslassungen zu rechnen ist. Man kann sich mit solchen Sachen böse in die Nesseln setzen, wenn auch nur eine Winzigkeit unbedacht bzw. falsch ist.
    jabu is offline Last edited by jabu; 21.11.2018 at 17:58.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •