User Tools

Site Tools


technology:eventualconsistency:comparetoimmediateconsistency

Eventual Consistency vs Transactional Save

Eventual consistency und die Konsequenzen daraus werfen so viele Fragen auf:

  • Was, wenn die Listensicht, die nach der Speicheraktion aufgerufen wird, noch nicht die neuesten Daten enthält?
  • Was, wenn der Druck, den ich aufrufe1), noch nicht die neuesten Daten enthält,
  • Was, wenn mengenbasierte/Aggregate übergreifende Prüfungen noch nicht die aktuellsten Daten enthalten?

Diese Fragen mussten bisher nicht gestellt werden, weil bisher alles immer transaktional gespeichert wurde2). Es wurde ganz naiv an die Sache ran gegangen. Es wurde geguckt, welche Daten für die späteren Sichten benötigt wurden, und beim Speichern einer Änderung wurden alle diese Daten einfach in der Speicher Transaktion mit geändert. Ich musste mir nie Gedanken über eine Aufteilung der Daten machen, darüber ob sie

  • alle zum selben Kontext gehören,
  • eine Relevanz für die Geschäftsprozesse haben oder für die Anzeigelogik3),
  • und vieles mehr.

Es wurde alles zusammen geworfen. Wenn eine Speicheraktion länger dauerte, wurde sie soweit optimiert, bis es akzeptabel war. Sichten auf Daten mussten sich aus den synchron gespeicherten Daten bauen lassen. Um das sicher zu stellen, wurden entweder die Daten erweitert, die gespeichert wurden, oder die Sichten wurden mit JOINs und/oder dynamischen Aufbau soweit optimiert, bis das Antwortzeitverhalten akzeptabel war.

Es gab einige wenige Reports, die einmal am Tag gebaut wurden4). Dem Anwender war klar, dass diese Reports im Schnitt 12 Stunden veraltet waren, d.h. hier war den Anwender informiert/geschult. In einigen Fällen wusste der Anwender auch, wie er den Report aktualisieren konnte5). Er wusste, dass die Aktion Zeit in Anspruch nehmen würde und konnte nebenbei andere Tätigkeiten durchführen.

Das Programmiererleben war so schön einfach. Jetzt, wo es die Option der schließlichen Konsistenz gibt, ist alles viel komplizierter geworden. Mit neuen Möglichkeiten kommen neue Entscheidungen, und die sind in diesem Fall gar nicht so leicht zu treffen.

Vorteile der schließlichen Konsistenz

Eventual consistency gepaart mit event sourcing hat zwei große Vorteile. Der erste ist der, dass man sich bei der Durchführung von Befehlen keine Gedanken machen muss, was für Projektionen/Sichten/Reports es später auf die Daten geben wird. Man speichert die Ereignisse6), die das Ergebnis der Befehlsausführung sind. Frei und flexibel hinzufügbare Denormalisierer schreiben die Änderungen aus den Ereignissen dann in die entsprechenden Sichten, die für Anzeigen und Reports benötigt werden.

Der zweite Vorteil ist der, dass man die Speicheraktion schlank, und somit schnell halten kann. Ich speichere nur die Ereignisse. Vielleicht gibt es 8 Sichten, die die neuen Änderungen benötigen. Aber warum jetzt auf die Denormalisierung für diese 8 Sichten warten? Meist wird immer nur eine von den acht als nächstes aufgerufen, und die anderen sieben dann irgendwann später. Wenn ich also nur die eine Sicht aktualisiere, hat der Anwender die Daten dafür sofort zur Verfügung. Wenn er eine der anderen Sichten aufruft, hat das System die Daten dafür inzwischen mit hoher Wahrscheinlichkeit bereits denormalisiert. Wenn nicht, warte ich halt dann nochmal kurz, bis das System so weit ist7).

Alles sofort zu Speichern heißt, dass der Anwender immer warten muss, und zwar mit einer Dauer von SUMN=1 to number of Denormalizations(DurationN). Auf Reports, die lange dauern, muss der Anwender warten, bis die Erzeugung angestoßen wird, was oft nur täglich ist, also eine Wartezeit von bis zu 24 Stunden bedeutet.

Mit eventual consistency speichern, heißt, dass der Anwender nur mit einer Dauer von Duration1 warten muss, also nur auf die Denormalisierung der Daten für die eine Sicht, die er als nächstes aufruft. Wenn er jede weitere aufruft, ist die mit einer Wahscheinlichkeit von PN bereits denormalisiert, d.h. er wartet in Summe insgesamt Duration1 + SUMN=2 to number of Denormalizations((1-PN)*DurationN), was deutlich kürzer sein kann, wenn PN deutlich größer als 0 ist, i.d.R. ziemlich nahe an 1.

Zudem wartet der Anwender nicht jedes mal lange nach der Speicheraktion, sondern immer nur kurz auf eine der Denormalisierungen. Anstatt also vielleicht einmal 5 Sekunden zu warten, und danach 8 mal eine Sekunde pro Sicht, wartet er beim ersten mal 1 Sekunde, und dann 8 mal 1,5 Sekunden pro Sicht. Und wenn er 10 Datenänderungen macht, und die 8 Sichten erst ganz zum Schluss aufruft, wartet er 10 mal eine Sekunde + 8 mal 1,5 Sekunden = 22 Sekunden anstatt 10 mal 5 Sekunden und dann 8 mal eine Sekunde = 58 Sekunden! Warum soll er nach jeder Speicheraktion auf die Denormalisierungen warten, die er vielleicht erst benötigt, nachdem er mehrmals gespeichert hat. Nehmen wir mal an, dem Anwender werden pro Tag 30 Sekunden Wartezeit erspart. Das sind pro Jahr8) 110 Minuten = fast 2 Stunden. Pro Anwender ist die Änderung pro Jahr ca. EUR 100,- Wert. Wenn ein Unternehmen 1.000 Anwender hat, und das Produkt 10 Jahre einsetzen wird, wären das ein Wert von EUR 1.000.000,-. Bei 20 solcher Kunden würde man der Wirtschaft Kosten von EUR 20.000.000 sparen!

Ich meine, dafür kann man ein paar Tage oder auch Wochen mehr Aufwand aufwenden, um das System dahingehend zu optimieren.

Die Schwierigkeit und Bestimmbare Konsistenz

Es gibt meines Wissens nach keine Methode, explizit auf eine Denormalisierung zu warten. Man kann zwar nach einzelnen Ergebnissen pollen, wenn ich aber einen Report über diverse Daten von unterschiedlichen Mitarbeitern öffnen möchte, habe ich nichts zum pollen. Was ich gerne hätte wäre etwas, was genau zwischen sofortiger und schließlicher Konsistenz liegt, eine sogenannte bestimmbare Konsistenz. Daten werden zwar nicht transaktional gespeichert, ich kann aber beim Aufruf von Sichten bestimmen, welche Daten(version) ich benötige9). Zur Not warte ich darauf, bis die Denormalisierung aufgeholt hat.

Der Vorteil des Systems muss sein, dass die Sichten in den meisten Fällen bereits aktuell sind, wenn ich danach frage, und dass die Zeitverzögerung, die dadurch entsteht, dass ich eine bestimmte Version der Daten anfrage, gering ist im Vergleich zu der Zeitverzögerung die durch ein synchrones Speichern entsteht. Am einfachsten ist es, wenn die Version mit den Daten mit geliefert wird, damit keine zwei Anfragen nötig sind.

Die Frage der Fragen ist nur, was man als Datenversion nimmt. Was macht die Konsistenz bestimmbar? Wenn das System mehrere Kontexte hat, die einzelnen Kontexte u.U. auch noch partitioniert sind, dann gibt es nicht die eine globale Version, nach der man Fragen kann. Wenn ich als Projektverantwortlicher eine Rechnung stellen möchte, will ich, dass alle Zeiten berücksichtigt werden, die bis zum dem Zeitpunkt, an dem ich die Schaltfläche betätige, gespeichert waren. Schließliche Konsistenz ist an dieser Stelle inakzeptabel.

Wenn man keine zentrale, globale Versionsvergabe für Ereignisversionen einrichten möchte10), bleibt am Ende nur eine Möglichkeit übrig: Der Zeitstempel als Identifizierungsmerkmal der Datenversion. Mann kann alle Rechner aller Partitionen koordinieren, damit sie dieselbe Uhrzei haben - das wäre die Voraussetzung dafür, dass das System der bestimmbaren Konsistenz einwandfrei funktioniert11).

1) z.B. ein Tätigkeitsbericht für den Kunden
2) in meinen Anwendungen
3) 2 unterschiedliche Kontexte
4) meist in der Nacht, z.B. um 4 Uhr morgens
5) mich anrufen und bitten, dass ich die Erstellung ansotße ;-)
6) Domain Events
7) hier ist das Problem
8) 52 Wochen abzgl. 6 Wochen Urlaub und 2 Wochen Feiertage = 44 Wochen * 5 Wochentage = 220 Tage
9) daher bestimmbar
10) weil das komplette System dann von der Verfügbarkeit dieses Dienstes abhängen würde und zudem alle Versionsvergabeaktionen serialisiert sein müssten, über alle Kontexte und Partitionen!
11) wobei es IMMER eventuell konsistent wäre
technology/eventualconsistency/comparetoimmediateconsistency.txt · Last modified: 2013/01/19 15:06 by rtavassoli