Das nachfolgende Azure/C#-Beispielprojekt zeigt, wie man ohne Transaktionen mit den Azure Storage-Services (zeitlich verzögerte) Konsistenz sicherstellen kann. Demonstriert wird dies anhand zwei TableStorage-Entitäten, Profiles und Postings: Pro Profile (Benutzerprofil) kann es mehrere Postings geben, wobei das letzte Posting, sowie die Anzahl der Postings auch im Profil redundant gespeichert werden. Somit müssten eigentlich Transaktionen verwendet werden. Allerdings gibt es die in TableStorage, u. a. aus Skalierungsgründen (siehe mein letztes Posting), nicht.
Zeitlich verzögerte Konsistenz kann aber auch mit Hilfe von Message-Queues hergestellt werden. Zum einen wird eine Message mit den zu ändernden Einträgen in Profiles und Postings in eine Queue geschrieben. Da dies nur eine Anweisung benötigt, handelt es sich hierbei um eine atomare Aktion. Die Nachricht wird gelesen und die Änderungen werden durchgeführt.
Scheitert dies, so wird die Nachricht _nicht_ aus der Queue gelöscht und das System befindet sich nun in einem inkonsistenten Zustand. Allerdings wird dann die Nachricht nach einiger Zeit wieder gelesen und bearbeitet. Somit sollte, sofern es sich nicht um einen Software-Fehler handelt, irgendwann die beiden Tabellen aktualisiert und das System somit wieder konsistent werden.
Auf zwei Dinge muss geachtet werden:
- Die Aktionen müssen Idempotent sein
- Poison-Messages müssen erkannt werden
Updates sollten per se idempotent sein, sofern kein anderer zwischenfunkt. Letzteres wird aber durch optimitische Concurrency-Checks von den Table-Services verhindert. Inserts müssen als InsertOrUpdate oder InsertOrDoNothing implemeniert werden und die ID muss von Anfang an bekannt sein, um zu verhindern, dass sie doppelt vorkommen. Die Tatsache, ob die Anzahl der Postings im Profil bereits erfolgreich hochgezählt wurde, muss auch irgendwo vermerkt werden um ein mehrfaches hochzählen für ein Posting zu vermeiden. Dafür wird eine Spalte in der Entität Profiles verwendet.
Poison-Messages sind Nachrichten, die immer wieder zum Scheitern der damit assoziierten logischen Transaktion führen. Diese werden durch den Dequeue-Count erkannt, der pro Abrufen aus der Queue automatisch hochgezählt wird. Überschreitet dieser den Wert 10 wird die Nachricht nicht mehr bearbeitet, sondern in eine Poison-Queue verschoben.
http://www.softwarearchitekt.at/downloads/Twittr.zip