Verteilte Systeme
Verteilte Transaktionen und
Nebenläufigkeitskontrolle
Transaktionen
Motivation
Wir haben im letzten Kapitel bereits das Konzept des gegenseitigen Ausschlusses bei Zugriff auf kritische Abschnitte betrachtet.
Ziel: eine bestimmte Ressource soll nur von einem Client zur selben Zeit benutzt werden
Ganz generell haben Transaktionen dasselbe Ziel: Schutz von Ressourcen vor gleichzeitigem Zugriff.
Transaktionen gehen jedoch noch wesentlich weiter:
– Automatisches Erzwingen der Konsistenzwahrung
– Es ist möglich, auf mehrere Ressourcen in einer einzigen atomaren Operation zuzugreifen, d.h. Umgang mit verschiedenen kritischen Abschnitten
– Diverse Arten von Fehler können abgefangen werden, so daß Prozesse in den Zustand vor Beginn der Ausführung einer Transaktion zurückgesetzt
Beispiel
Wir wollen die in diesem Kapitel vermittelten Konzepte anhand eines durchgängigen Beispiel erläutern.
Es gibt zwei Arten von Ressourcen:
– Account-Objekte (Konto-Objekt), die Abbuchungen und Einzahlungen gestatten sowie Abfragen und Änderungen des Kontostands
– Branch-Objekte (Bankfiliale-Objekt), die eine Filiale
repräsentieren und es gestatten, Konten zu erzeugen,
Konten zu suchen und den Gesamtstand aller Konten in
dieser Filiale abzufragen.
Beispiel: Methoden
Methoden des Branch-Objekts
create(name) -> account Erzeugt neues Konto name
lookUp(name) -> account Gibt Verweis auf Konto name zurück
branchTotal() -> amount Gibt Gesamtsumme aller Konten zurück
Methoden des Account-Objekts
deposit(amount)
Zahlt amount (Betrag) auf Konto ein
withdraw(amount)
Hebt amount von Konto ab
getBalance() -> amount Gibt Kontostand zurück
setBalance(amount)
Setzt Kontostand auf amount
Einfache Synchronisation
(ohne Transaktion)
Im Account-Objekt müssen die Operationen deposit() und withdraw() atomar ausgeführt werden, d.h. sie dürfen in der Ausführung nicht unterbrochen werden.
In Java läßt sich das auf einfache Weise unter Verwendung des Schlüsselwortes synchronized erreichen:
public synchronized void deposit(...);
Ergebnis: wenn mehrere Threads gleichzeitig dieselbe bzw.
eine andere synchronisierte Methode dieses Objekts
benutzen wollen, wird nur ein Thread zugelassen; die
anderen werden blockiert.
Fehlermodell für Transaktionen
B.W. Lampson führte 1981 ein Fehlermodell ein, das heute als Grundlage aller Transaktionsalgorithmen verwendet wird.
Ein Algorithmus muß demnach folgende (vorhersehbare) Fehler behandeln können:
– Fehler beim Schreibzugriff auf permanenten Speicher – Server-Absturz
– Beliebige Verzögerungen bei der Nachrichtenübertragung
Im Katastrophenfall keine Aussage über die Folgen.
– Schreiben in falschen Block ist Katastrophe
– Gefälschte Nachrichten sowie nicht erkannte fehlerhafte
Transaktionen
Transaktionen bestehen aus einer Folge von Operationen (Anfragen an Server), für die bestimmte Eigenschaften gelten – die ACID-Eigenschaften.
Beispiel für eine Transaktion in der Bankanwendung:
– eine Kunde will verschiedene Operationen auf drei Konten a, b und c ausführen.
– Die Operationen sollen ohne Unterbrechung ausgeführt werden.
– Transaction T:
a.withdraw(100);
b.deposit(100);
c.withdraw(200);
b.deposit(200);
Transaktionen: ACID-Eigenschaft
ACID ist ein von T. Härder und A. Reuter 1983 vorgeschlagenes Acronym.
Bedeutung:
– – Atomicity: Alles-oder-Nichts A Eigenschaft: Die Transaktion wird entweder vollständig ausgeführt oder hinterläßt keine Wirkung.
– – Consistency: eine Transaktion überführt das System von C einem konsistenten Zustand in einen konsistenten Zustand.
– – Isolation: jede Transaktion muß von der Ausführung anderer I Transaktionen unabhängig bleiben (Serialisierbarkeit).
– – Durability: Die Änderungen einer beendeten und bestätigten D
ACID (1): Atomarität und Dauerhaftigkeit
Atomicity und Durability
– ist gefährdet durch eine fehlerhafte Umgebung und
– wird erreicht durch die Verwendung wiederherstellbarer Objekte.
Wenn ein Server-Prozeß während der Abarbeitung einer Transaktion abstürzt und dann ein neuer Prozeß gestartet wird, dann muß dieser den alten Zustand der Objekte wieder laden können.
Wenn die Transaktion abgeschlossen ist, muß das Objekt den neuen Zustand repräsentieren und abgespeichert
werden.
Implementierung
Für jede Transaktion gibt es einen Koordinator (Transaction Monitor), der den Ablauf steuert.
Verwendung:
– Der Client startet eine Transaktion, woraufhin der Koordinator eine Transaktions-ID (TID) allokiert und zurückgibt.
– Dann werden die Operationen ausgeführt.
– Am Ende ruft der Client ein
closeTransaction()auf,
woraufhin der Koordinator alle Objekte speichert und eine positive oder negative Abschlussmeldung liefert.
– Der Client kann auch von sich aus die Transaktion
Implementierung: Methoden
openTransaction() -> trans;
startet eine neue Transaktion und gibt die
eindeutige TID
transzurück. Diese ID wird in den anderen Operationen der Transaktion verwendet.
closeTransaction(trans) -> (commit, abort);
beendet eine Transaktion: der Rückgabewert
commitzeigt an, daß die Transaktion festgeschrieben wird; der Rückgabewert
abort
zeigt an, daß sie abgebrochen wurde.
abortTransaction(trans);
bricht die Transaktion
transab.
Beispiel: Java TransactionManager
Findet sich in javax.transaction.
Ausschnitt aus der Schnittstelle:
– void resume(Transaction tobj)
Resume the transaction context association of the calling thread with the transaction represented by the supplied Transaction object.
– void suspend()
Suspend the transaction currently associated with the calling thread and return a Transaction object that represents the transaction context being suspended.
– Transaction rollback()
Roll back the transaction associated with the current thread – void getTransaction()
Get the transaction object that represents the transaction context of the calling thread
– Transaction commit()
Complete the transaction associated with the current thread
Implementierung: Transaktions-ID
Bei jeder Operation, die ein Client für eine Transaktion durchführt, muß er die Transaktions-ID (TID) angeben.
Mögliche Implementierungen:
– Angabe als zusätzlicher Parameter in den Operationen, z.B.
deposit(trans, amount)– Bei Verwendung von Middleware wird die TID
üblicherweise implizit bei allen entfernten Aufrufen
angegeben, z.B. beim CORBA CORBA Transaction Transaction Service. Der Service Anwendungsprogrammierer muß sich darum nicht
kümmern.
Beispiel: Transaktionshistorie
Successful Aborted by client Aborted by server
openTransaction openTransaction openTransaction
operation operation operation
operation operation operation
server aborts transaction
operation operation operation ERROR
reported to client closeTransaction abortTransaction
Geschachtelte Transaktionen
Geschachtelte Transaktionen erweitern das bisherige (flache)
Transaktionsmodell, indem sie gestatten, daß Transaktionen aus anderen Transaktionen zusammengesetzt sind.
Die Transaktion auf der höchsten Ebene wird als toplevel transaction bezeichnet, die anderen als subtransactions.
Zusätzliche Nebenläufigkeit:
– Subtransactions auf der selben Hierarchieebene können nebenläufig ausgeführt werden
– Bankenbeispiel: die Operation branchTotal() muß für sämtliche Konten die Methode getBalance() aufrufen. Man könnte jeden dieser Aufrufe als Untertransaktion starten
Unabhängiges Commit oder Abort:
– Dadurch werden Transaktionen potentiell robuster (hängt von der Anwendung ab)
– Die Elterntransaktion muß jeweils entscheiden, welche Folge ein Abort der Untertransaktion haben soll.
Geschachtelte Transaktion: Regeln
1. 1. Eine Transaktion darf nur abgeschlossen werden, wenn ihre Untertransaktionen abgeschlossen sind.
2. Wenn 2. eine Untertransaktion abschließt, entscheidet sie
unabhängig, entweder provisorisch festzuschreiben (commited) oder endgültig abzubrechen.
3. Wenn 3. eine Elterntransaktion abbricht, werden auch alle Subtransaktionen abgebrochen.
4. Wenn 4. eine Subtransaktion abbricht, entscheidet die Elterntransaktion, was weiter geschieht.
5. Wenn 5. eine Elterntransaktion festgeschrieben ist, dann können
alle provisorisch festgeschriebenen Untertransaktionen ebenfalls
Transaktionen: ACID-Eigenschaft
ACID ist ein von T. Härder und A. Reuter 1983 vorgeschlagenes Acronym.
Bedeutung:
– – Atomicity: Alles-oder-Nichts A Eigenschaft: Die Transaktion wird entweder vollständig ausgeführt oder hinterläßt keine Wirkung.
– – Consistency: eine Transaktion überführt das System von C einem konsistenten Zustand in einen konsistenten Zustand.
– – Isolation: jede Transaktion muß von der Ausführung anderer I Transaktionen unabhängig bleiben (Serialisierbarkeit).
– – Durability: Die Änderungen einer beendeten und bestätigten D
(committed) Transaktion können weder verloren gehen noch
rückgängig gemacht werden.
ACID (2): Isolierung und Konsitenz
Die Operationen aller Transaktionen müssen so synchronisiert werden, daß Isolation und Consistency erreicht werden.
Die beiden Eigenschaften sind gefährdet durch Interferenzen nebenläufiger Transaktionen.
Einfachste Variante: Serielle Ausführung der Transaktionen
Ist nicht wünschenswert, da die Performance des Servers sehr schlecht wäre und mögliche nebenläufige Ausführungen von Transaktionen würden nicht berücksichtigt.
Zur Maximierung der Leistung wird deshalb versucht, die
Nebenläufigkeit zu maximieren: Zwei Transaktionen dürfen
nebenläufig ausgeführt werden, wenn diese Ausführung
Nebenläufigkeitskontrolle
Nebenläufigkeitskontrolle
Nebenläufigkeitskontrolle (Concurrency Control) ist die wichtigste Aufgabe des Transaktionsmanagers, um die Nebenläufigkeit maximieren zu können.
Aufgabe: finde möglichst nebenläufige Ablaufpläne für Transaktionen, ohne das serielle Äquivalentskriterium zu verletzen.
Es geht also im wesentlichen darum, miteinander in Konflikt
stehende Operationen korrekt einzuplanen.
Interferenzen nebenläufiger Transaktionen
Transaction T:
balance = b.getBalance();
b.setBalance(balance*1.1);
a.withdraw(balance/10)
Transaction U:
balance = b.getBalance();
b.setBalance(balance*1.1);
c.withdraw(balance/10);
balance = b.getBalance();
b.setBalance(balance*1.1);
a.withdraw(balance/10);
$200
balance = b.getBalance();
b.setBalance(balance*1.1);
c.withdraw(balance/10);
$200
$220
$220
$20 $20
Problem der verlorenen Updates
Problem der verlorenen Updates
Korrekte Interferenz
Transaction T:
balance = b.getBalance();
b.setBalance(balance*1.1);
a.withdraw(balance/10)
Transaction U:
balance = b.getBalance();
b.setBalance(balance*1.1);
c.withdraw(balance/10);
balance = b.getBalance();
b.setBalance(balance*1.1);
a.withdraw(balance/10);
$200
balance = b.getBalance();
b.setBalance(balance*1.1);
c.withdraw(balance/10);
$220
$242
$220
$20 $22
Interferenzen nebenläufiger Transaktionen
Problem der
inkonsistenten Abrufe Problem der
inkonsistenten Abrufe
$200 == a.getBalance()
$200 == b.getBalance() Transaction V:
a.withdraw(100) b.deposit(100) a.withdraw(100);
b.deposit(100)
Transaction W:
aBranch.branchTotal()
total = a.getBalance()
total = total+b.getBalance() total = total+c.getBalance()
$100
$300
$100
$300
Korrekte Interferenz
$200 == a.getBalance()
$200 == b.getBalance() Transaction V:
a.withdraw(100) b.deposit(100) a.withdraw(100);
b.deposit(100)
Transaction W:
aBranch.branchTotal()
total = a.getBalance()
total = total+b.getBalance() total = total+c.getBalance()
$100
$400
$100
$300
Wiederherstellung nach Abbrüchen
Vorzeitiges Schreiben Vorzeitiges Schreiben Dirty Read
Dirty Read Transaction T:
balance = a.getBalance();
a.setBalance(balance +10);
Transaction U:
balance = a.getBalance();
a.setBalance(balance +20);
balance = a.getBalance();
a.setBalance(balance +10);
abort transaction;
$100
balance = a.getBalance();
a.setBalance(balance +20);
commit transaction;
$110
$130
$110
a.setBalance(105); a.setBalance(110);
a.setBalance(105);
abort/commit transaction;
$105
a.setBalance(110);
commit/abort transaction;
$110 Kaskadenartige Abrüche
Kaskadenartige Abrüche
Nur vorläufiges commit! Nur vorläufiges commit!
Konflikte zwischen Operationen
Was bedeutet es, wenn zwei Operationen zueinander im Konflikt stehen?
Ö Ihr kombinierter Effekt hängt von der Reihenfolge ab, in der sie ausgeführt werden.
Mit diesem Begriff läßt sich serielle Äquivalenz formaler definieren:
Ö Zwei Transaktionen sind genau dann seriell äquivalent, wenn alle Paare von miteinander in Konflikt stehenden
Operationen der beiden Transaktionen auf allen betroffenen
Objekten in derselben Reihenfolge ausgeführt werden.
Beispiel: Konfliktregeln für read & write
Operationen unter-
schiedlicher Transaktionen
Konflikt Grund
read read Nein Weil die Wirkung eines Paares von read-Operationen nicht von der Aus- führungsreihenfolge abhängig ist.
read write Ja Weil die Wirkung einer read- und einer write-Operation von der Aus- führungsreihenfolge abhängig ist.
write write Ja Weil die Wirkung eines Paares von write-Operationen von der Ausführ- ungsreihenfolge abhängig ist.
Beispiel: Serielle Äquivalenz
Gegeben seien zwei Transaktionen wie folgt:
– T: x=read(i); write(i,10); write(j,20);
– U: y=read(j); write(j,30); z=read(i);
Ist der folgende Ablauf seriell äquivalent?
Warum bzw. warum nicht?
Transaction T: Transaction U:
Der Zugriff auf einzelne Objekte ist serialisiert:
•T greift auf i vor U zu
•U greift auf j vor T zu Aber: Nicht äquivalent!
Korrekt wäre zB:
T greift vor U auf i zu und T greift vor U auf j zu
x = read(i) write(i, 10)
write(j, 20)
y = read(j) write(j, 30) z = read(i)
Beispiel: Serielle Äquivalenz
Wie im Beispiel U vor T
T vor U
Ausgangswerte
x y z i j
- - - * **
* 20 10 10 20
30
* ** * 10 30
20
* ** 10 10 30
20
Beispiel ist nicht seriell Äquivalent:
weder zu „ T vor U“ noch zu „U vor T“
Serielle Äquivalenz entscheidet nicht über „T vor U“ oder „U vor T“: serielle Äquivalenz sorgt dafür, daß eines von beiden im Ergebnis erzielt wird!
Architektur eines Transaktionssystems
Transaktionen
Transaktionsverwalter (transaction manager)
Planer
(scheduleranager)
Rücksetzer
(recovery manager)
start, end, read, write, abort, commit
Erhaltung und Wiederherstellung der Daten und ihrer Konsistenz, d.h. Rücksetzung von
Transaktionen (Recovery)
Koordination von Transaktionen (Nebenläufigkeitskontrolle/
Concurrency Control) read, write, abort, commit
read, write, lock, release, abort, commit
read, write
Nebenläufigkeitskontrolle: Algorithmen
Es geht also nun darum, einen Ablaufplan für zueinander in Konflikt stehende Operationen zu finden.
Drei gängige Ansätze:
– Sperren (Locking): pessimistische Systeme
– optimistsiche Nebenläufigkeitskontrolle (Optimistic concurrency control)
(Auswertung ganze Transaktion)
– Zeitstempel-Reihenfolge (Timestamp ordering)
(Auswertung einzelne Operation)
Sperren
Sperren
Älteste und am weitesten verbreitete Form der Nebenläufigkeitskontrolle
Einfachste Variante: exklusive Sperren
– Wenn ein Prozeß Zugriff auf eine Ressource (ein
Datenobjekt) benötigt, bittet er den Planer (über den Transaktionsmanager) um eine exklusive Sperre
– Wenn er sie erhalten hat und seine Arbeit anschließend beendet hat, gibt er die Sperre wieder zurück
Aufgabe des Planers: Vergabe der Sperren in einer Weise,
daß nur serielle äquivalente Abläufe entstehen
Sperren: Beispiel
Transaction T:
balance = b.getBalance();
b.setBalance(balance*1.1);
a.withdraw(balance/10)
Transaction U:
balance = b.getBalance();
b.setBalance(balance*1.1);
c.withdraw(balance/10);
openTransaction
bal = b.getBalance();
b.setBalance(balance*1.1);
a.withdraw(balance/10);
closeTransaction
openTransaction
bal = b.getBalance();
...
b.setBalance(balance*1.1);
c.withdraw(balance/10);
closeTransaction
Operationen Sperren
Wartet auf Sperre
B sperren C sperren Sperren aufheben
Operationen Sperren
B sperren A sperren Sperren aufheben
2-Phasen-Sperren
Bekannter Algorithmus, von dem bewiesen ist, daß er seriell äquivalente Ablaufpläne erstellt, wenn sich alle Transaktionen daran halten.
Ähnlich wie bei kritischen Abschnitten werden Sperren benutzt, um in Konflikt stehende Operationen (und damit die aufrufende Transaktion) zu verzögern.
Da Lesezugriffe sich gegenseitig nicht stören, werden zwei Sorten von Sperren vorgesehen: Lesesperren und Schreibsperren
Die Menge der Operationen erweitert sich daher um die Sperroperationen:
– Ist eine Lesesperre gesetzt, so können noch weitere Lesesperren gesetzt werden, aber keine Schreibsperre.
– Ist eine Schreibsperre gesetzt, so können keine weitere Sperren zugelassen werden.
– Lesesperren werden auch geteilte Sperren, Schreibsperren auch exklusive Sperren genannt.
2-Phasen-Sperren: Anforderungen
1. Eine Transaktion muß jedes Datenelement vor dem ersten Zugriff mit einer dem Zugriff entsprechenden Sperre belegen.
2. Kein Datenelement darf mit unverträglichen Sperren belegt werden.
3. Eine Transaktion darf nach der ersten Freigabe einer Sperre keine weitere Sperre setzen.
4. Am Ende der Transaktion müssen alle von ihr gehaltenen Sperren freigegeben sein.
Forderungen 3 und 4 geben dem Sperrprotokoll seinen Namen:
– eine, in der Sperren sukzessive erworben werden und
– eine, in der die Sperren
Striktes 2-Phasen-Sperren
Das normale Zwei-Phasen-Sperren erzeugt serialisierbare Pläne, jedoch nicht unbedingt rücksetzbare.
Daher zusätzliche Forderung:
5. Alle jemals erworbenen Sperren werden bis
zum Ende der Trans- aktion gehalten.
Dadurch werden
strikte Pläne erzeugt,
die rücksetzbar sind.
Zwei-Phasen-Sperren: Anmerkungen
Das strikte Zwei-Phasen-Sperren ist das in der Praxis übliche Verfahren.
Die Sperren müssen nicht vom Programmierer gesetzt werden, sondern werden automatisch vom Planer eingefügt und verwaltet.
Das Zwei-Phasen-Sperren kann (mit Ausnahme der konservativen Variante, alle Sperren am Anfang in einer atomaren Operation zu erwerben) zu Verklemmungen (deadlocks) führen.
Was die Einheit der Sperrung ist, hängt vom Einsatzgebiet der
Transaktionen ab: Das Spektrum reicht von einzelnen Werten über Sätze bis hin zu Mengen von Dateien. (Sperrgranularität)
– kleine Dateneinheiten (feine Granularität) ermöglicht hohe
Nebenläufigkeit, bedeutet aber großen Aufwand zur Verwaltung der Sperren
– große Dateneinheiten (grobe Granularität) reduziert die
Zwei-Phasen-Sperren: Deadlock
Transaktion T Transaktion U
Operationen Sperren Operationen Sperren
a.deposit(100); Schreibsperre für a
b.deposit(200) b.withdraw(100)
a.withdraw(200);
Wartet auf die Sperre, die U für b hält
Schreibsperre für b
Wartet auf die Sperre, die T für a hält
b a
wartet auf gehalten von
T U
gehalten von
wartet auf
Deadlock
Ein Deadlock (Verklemmung) ist ein Zustand, in dem jedes Mitglied einer Gruppe von Transaktionen darauf wartet, daß ein anderes Mitglied eine Sperre freigibt.
Je feiner die Granularität bei der Nebenläufigkeitskontrolle ist, desto geringer ist die Gefahr von Deadlocks.
Frage: kann man Deadlocks erkennen bzw. verhindern?
Transaktionen Wartebeziehung
U
Warte-Graph
TWarte-Graph
Lösung 1: Ausschließen (Prevention)
Einfache Lösung 1.1: Erwerbe am Anfang der Transaktion die Sperren für alle benötigten Objekte (konservatives Zwei-Phasen-Sperren)
– Erwerb der Sperren muss als atomare Aktion durchgeführt werden – Verhindert Deadlocks, ist aber zu restriktiv
– Außerdem kann es z.B. bei interaktiven Transaktionen sein, daß am Anfang nicht bekannt ist, welche Objekte benötigt werden.
– Eher selten verwendete Lösung
Einfache Lösung 1.2: (vordefinierte) Ordnung auf Sperren (bzw.
Objekten); Anfordern der Sperren in dieser Reihenfolge – Vorzeitiges Sperren
falls ein Objekt erst später bearbeitet wird, dessen Sperre aber vorher in der Ordnung liegt
falls nicht bekannt ist, welche Objekte benötigt werden – reduzierte Nebenläufigkeit
Lösung 1: Ausschließen (Prevention)
Ordnung für Sperren: a vor b
Transaktion T Transaktion U
Operationen Sperren Operationen Sperren
a.deposit(100); Schreibsperre für a
b.deposit(200) b.withdraw(100)
a.withdraw(200);
Schreibsperre für b
Warten auf
Schreibsperre für a Dann
Schreibsperre für b Alle Sperren
freigeben
Alle Sperren freigeben
Lösung 2: Erkennen (Detection)
Deadlocks werden am Warte-Graph erkannt: enthält er einen Zyklus, ist das System in einem Deadlock.
– Dazu kann ein entsprechender Standard-Graphen-Algorithmus verwendet werden (Graphentheorie).
– Es muß dann eine Transaktion herausgesucht werden, deren Abbruch zum Brechen des Zyklus führt.
Möglichkeit 1: verwende Timeouts.
– Eine Sperre einer Transaktion ist für eine bestimmte Zeit unverletzlich;
danach kann sie gebrochen werden (Deadlock kann u.U. für diese Zeit nicht aufgelöst werden!)
– Verletzliche Sperren werden von Transaktionen gebrochen, die eine Sperre anfordern
– Eine Transaktion mit einer gebrochenen Sperre wird abgebrochen.
Deadlock: Beispiel
T, U und V teilen eine Lesesperre für c, während W eine Schreibsperre für b besitzt, auf das V zugreifen möchte (links).
Transaktionen T und W fordern nun eine Schreibsperre für Objekt c an (rechts).
Jedes Objekt wartet nur auf ein Objekt, trotzdem ist V in zwei Zyklen.
Lösung: breche V ab, dann werden die Zyklen aufgelöst
T
U
V
C
T
U Held by
Held by Held by
W
B Held by
Optimistische
Nebenläufigkeitskontrolle
Optimistische Nebenläufigkeitskontrolle
Erkenntnis: Sperren hat einige gravierende Nachteile:
– Sperren müssen immer verwendet werden, auch wenn es gar nicht nötig wäre (z.B. nur read) → unnötiger Overhead
– Gefahr von Deadlocks
– Reduzierung der Nebenläufigkeit durch spätes Abgeben von Sperren
Alternative: verwende den optimistischen Ansatz, wenn es sehr selten Konflikte geben wird.
Alle Transaktionen arbeiten, als wären sie die einzigen.
Nur, wenn ein Konflikt auftritt, muß am Ende eine der
Transaktionen abgebrochen werden und deren Ergebnisse
Phasen der Transaktionen
Nach H.T. Kung und J.T. Robinson 1981
Arbeitsphase (Working Phase):
Die Transaktion besitzt eine eigene Kopie (Versuchsversion) der notwendigen Daten und arbeitet auf diesen.
Bei read -Operationen: Wenn noch keine Kopie vorhanden ist, wird vom Original gelesen!
Auswertungsphase (Validation Phase):
Nach Abschluß der Operationen der Transaktion wird
überprüft, ob es Konflikte mit anderen Transaktionen gab.
Wenn ja, müssen diese Konflikte gelöst werden.
Aktualisierungsphase (Update Phase):
Wurde die Transaktion positiv validiert, werden die Daten permanent gemacht (festgeschrieben).
Implementierung als kritischer Bereich
vereinfacht die Auswertung!
Implementierung als kritischer Bereich
vereinfacht die Auswertung!
Auswertungsphase
Natürlich werden auch hier die Konfliktregeln verwendet, um die serielle Äquivalenz mit allen überlappenden
Transaktionen zu garantieren.
Überlappend: Transaktionen, die noch nicht festgeschrieben waren, als die neue Transaktion startete.
Transaktionen werden durchnummeriert (Zeitstempel) in der Reihenfolge ihres Eintritts in die Auswertungsphase
(
closeTransactiondes Clients).
Festschreibung: Transaktion T
iwird dann vor Transaktion T
vfestgeschrieben, wenn i < v.
Ist eine Transaktion ausschließlich lesend oder abgebrochen
Serialisierbarkeit einer Transaktion
Der Auswertungstest für eine Transaktion T
vbasiert auf den Konflikten mit der überlappenden Transaktion T
i.
Um die Serialisierbarkeit herzustellen, müssen die folgenden Regeln erfüllt werden
(Ti < Tv, erstes write erzeugt eine Kopie!):
Tv Ti Regel
write read 1. Ti darf keine von Tv geschriebenen Objekte lesen read write 2.
write write 3.
Tv darf keine von Ti „geschriebenen“ Objekte lesen Ti darf keine von Tv geschriebenen Objekte schreiben und Tv von Ti „geschriebenen“ Objekte
>
Jüngere Transaktion Tvhat zu schnell gelesen oder ältere Transaktion Ti hat zu langsam geschrieben Jüngere Transaktion Tvhat zu schnell gelesen oder ältere Transaktion Ti hat zu langsam geschrieben Jüngere Transaktion Tv hat zu schnell geschrieben oder ältere Transaktion Ti hat zu langsam gelesen Jüngere Transaktion Tv hat zu schnell geschrieben oder ältere Transaktion Ti hat zu langsam gelesen
Jüngere Transaktion Tvhat zu schnell geschrieben oder ältere Transaktion Ti hat zu langsam geschrieben Jüngere Transaktion Tvhat zu schnell geschrieben oder ältere Transaktion Ti hat zu langsam geschrieben
Auswertungsstrategien
Bei Rückwärtsauswertung werden die Regeln mit den vorhergehenden überlappenden Transaktionen - die vorher in die Auswertungsphase eingetreten sind überprüft.
Bei Vorwärtsauswertung werden die Transaktionen einbezogen, die noch nicht in die Auswertungsphase eingetreten sind.
Zuvor bereits
mit der Auswertung begonnene
Transaktionen Arbeitet Auswertung Aktualisierung
T1 T2
aktuell ausgewer-
tete Transaktion Tv
Noch auszuwer-
active1
active T3
Auswertungsstrategien: Algorithmen
Rückwärtsauswertung boolean valid = true;
//startTn größte Transaktions- nummer, als Tv startete
//finishTn + 1 = Tv
for (int Ti= startTn+1;
Ti <= finishTn; Ti++) {
// Regel 1 gilt // Tv > Ti
if (read_set of Tv intersects
write_set of Ti) valid = false; } // Regel 3 gilt
Vorwärtsauswertung
boolean valid = true;
// active1 - 1 = Tv
for (int Ti= active1; Ti <= activeN; Ti++) {
// Regel 1 gilt // Ti > Tv
if (read_set of Ti intersects
write_set of Tv) valid = false; } // Regel 3 gilt
Regel 1 und 3 gelten, da Tv erst nach der Auswertungsphase geschrieben wird (und alle Ti mit i<v bereits
vorher festgeschrieben sind und
während der Arbeitsphase auf Kopien geschrieben haben!)
Regel 1 und 3 gelten, da Tv erst nach der Auswertungsphase geschrieben wird (und alle Ti mit i<v bereits
vorher festgeschrieben sind und
während der Arbeitsphase auf Kopien geschrieben haben!)
Regel 1 und 3 gelten, da Ti erst nach der Auswertungsphase von Tv
geschrieben wird!
Regel 1 und 3 gelten, da Ti erst nach der Auswertungsphase von Tv
geschrieben wird!
Ti
Tv
Original
Kopie write
read Ti darf keine von Tv geschriebenen Objekte lesen
Ti
Tv
Original Kopie
write
read
Tv darf keine von Ti geschriebenen Objekte lesen
Ti darf keine von Tv und Tv von Ti geschriebenen Objekte schreiben Original
write Ti
Kopie write
Zeitstempel-Reihenfolge
Zeitstempel-Reihenfolge
Idee: jede Transaktion bekommt einen eindeutigen
Zeitstempel
ts(T)(ermittelt mit Hilfe von Lamport-Uhren)
Jede Operation einer Transaktion besitzt den Zeitstempel der Transaktion und wird sofort ausgewertet.
Zeitstempelreihenfolge gibt serielle
Ausführungsreihenfolge der Transaktionen vor!
Außerdem besitzt jedes Datenobjekt einen Lesezeitstempel
tsRD(x)
und einen Schreibezeitstempel
tsWR(x).
– tsRD(x)
enthält den Wert
ts(Ti), wobei
Tidie Transaktion ist, die als letzte lesend auf
xzugegriffen hat.
– tsWR(x)
enthält den Wert
ts(Ti), wobei
Tidie Transaktion
Konfliktlösung
Situation 1: der Planer erhält ein read(T,x) mit Zeitstempel ts.
– Wenn ts < tsWR(x), dann wurde die letzte write-Operation nach dem Start von T durchgeführt! T wird abgebrochen. Eine jüngere Transaktion hatte (zu früh) geschrieben.
– Wenn ts > tsWR(x), dann darf das read stattfinden. Eine ältere Transaktion hatte geschrieben.
Setze außerdem tsRD(x) auf max(ts,tsRD(x)).
Situation 2: der Planer erhält ein write(T,x) mit Zeitstempel ts.
– Wenn ts < tsRD(x)∨ ts < tsWR(x), dann wird T abgebrochen, da eine jüngere Transaktion x bereits gelesen oder geschrieben hat. T ist
sozusagen zu spät dran.
– Wenn aber ts > tsRD(x)∧ ts > tsWR(x), dann darf der Wert von x geändert werden, da keine jüngere Transaktion den Wert gelesen oder geschrieben hat.
Setze außerdem tsWR(x) auf ts.
Zeitstempel-Reihenfolge: Beispiel
Drei Transaktionen T1, T2, T3
T1 wurde abgeschlossen, bevor T2 und T3 begannen, d.h. alle read- und write-Zeitstempel stehen auf ts(T1).
T2 und T3 werden nebenläufig ausgeführt, mit ts(T2) < ts(T3).
Die Transaktionen arbeiten ohne Kopien, also direkt auf dem Original.
Betrachten wir einige Beispielsituationen (auf nächster Folie):
– Schreiben:
T2 schreibt x, ohne daß T3 bereits zugegriffen hätte [(a), (b)]
T2 schreibt x, aber T3 hat vorher gelesen [(c)] oder geschrieben [(d)]
– Lesen:
T2 liest x ohne Konflikt [(e), (f)].
In [(g)] hat T3 gelesen, T2 kann ohne Konflikt lesen.
Zeitstempel-Reihenfolge: Beispiel
Schreiben
Schreiben Lesen Lesen
(a)
tsRD(x) tsWR(x) ts(T2)
(T1) (T1) Zeit
(b)
tsWR(x) tsRD(x) ts(T2)
(T1) (T1) Zeit
(T2)
(T2)
(c)
tsWR(x) tsRD(x) ts(T2)
(T1) (T3) Zeit
(d)
tsRD(x) tsWR(x) ts(T2)
(T1) (T3) Zeit
(T2)
(T2)
OK
abort
(h)
tsRD(x) tsWR(x) ts(T2)
(T1) (T3) (T2) Zeit (e)
tsRD(x) tsWR(x) ts(T2)
(T1) (T1) Zeit
(f)
tsWR(x) tsRD(x) ts(T2)
(T1) (T1) Zeit
(T2)
(T2)
(g)
tsWR(x) tsRD(x) ts(T2)
(T1) (T3) (T2) Zeit
OK
abort
Zeitstempel-Reihenfolge: Beispiel 2
Um Abbrüche zu vermeiden, wird (wie bei der optimistischen Nebenläufigkeitskontrolle) mit Kopien gearbeitet
Original, d.h. write-Operationen wurden festgeschrieben
Kopie, d.h. write-Operationen wurden auf der Kopie ausgeführt
T
3: write -Operation T
3: write -Operation
T2 T3
T2 T2
Vor
Nach T1 T3
T1
T2
T4
T1 T4
T1
T3 T4
T4
T
3: read -Operation T
3: read -Operation
T2 T2 T4 T1 T2 T4
Fälle (d), (h) müssen so nicht abgebrochen werden, wenn die Kopie gehalten wird.
Nebenläufigkeitskontrolle: Reihenfolge
Jede Nebenläufigkeitskontrolle sorgt stets für eine serielle Äquivalenz!
Festlegung der Ausführungsreihenfolge für zwei „gleichzeitig“ gestartete Transaktionen U und T wird festgelegt
– Sperren: bei Vergabe der Sperren. U < T, T < U möglich.
– optimistische Nebenläufigkeitskontrolle: bei Eintritt in Auswertungsphase. U < T, T < U möglich.
– Zeitstempel-Reihenfolge: Beim Start der Transaktion
Die Nebenläufigkeit sorgt für serielle Äquivalenz, ist aber für „unsinnigen Inhalt“ der Transaktionen nicht verantwortlich!
Mit wachsender Anzahl an write-Operationen sollte von der optimistischen Nebenläufigkeit ohne Kopie zu der mit Kopie, dann zur Zeitstempel-
Reihenfolge ohne Kopie, dann mit Kopie und letztlich zu Sperren übergegangen werden.
Die Entscheidung ist durch Beobachtung des eigenen Systems, d.h.
aussagekräftigen statistischen Untersuchungen, zu sichern bzw. zu treffen.
Nebenläufigkeitskontrolle: Vergleich
Sperren
+ Gut geeignet für Transaktionen mit vielen Konflikten
– Bei dominierenden read-Operationen ist Zeitstempel-Reihenfolge besser – nicht Deadlock-frei
optimistsiche Nebenläufigkeitskontrolle + Deadlock-frei
+ Maximale Ausnutzung von Nebenläufigkeit, deshalb sehr gut bei konfliktfreien Situationen
– Transaktionen müssen manchmal wiederholt werden (vor allem schwierig unter hoher Last, Verhungern einer Transaktion möglich!)
Zeitstempel-Reihenfolge + Deadlock-frei
– Bricht Transaktionen auch ab, wenn es bei Sperren nicht nötig wäre
Wiederherstellung
Fehlerarten
Für Transaktionssysteme sind drei verschiedene Arten von Fehlern zu unterscheiden
TransaktionsfehlerTransaktionsfehler
– Ursachen: Interne Konsistenzverletzung; Entscheidung des Transaktionsmanagementsystems
– Häufigkeit: ca. 1 mal in der Sekunde
– Maßnahmen: Jegliche Wirkung dieser Transaktion ungeschehen machen (undo)
– Benötigte Zeit: etwa so lange wie eine erfolgreiche Transaktionsverarbeitung
SystemabbruchSystemabbruch
– Ursachen: Fehler im BS; Hardwareausfall (Stromversorgung); Fehler im Transaktionsmanagementsystems
Fehlerarten
– Maßnahmen: Wiederherstellung des letzten bestätigten Zustands, evtl. Nachführen bestätigter aber verlorengegangener Änderungen (redo), evtl. Rückgängigmachen von Änderungen nicht bestätigter Transaktionen (undo)
– Benötigte Zeit: ein paar Minuten
Ausfall von SpeichermedienAusfall von Speichermedien
– Ursachen: Fehler im BS (Treibersoftware); Hardwarefehler: Kanal, Steuereinheit, Bus; Mechanische Zerstörung (head crash); Verlust der Magnetisierung
– Häufigkeit: ca. 1 mal im Jahr
– Maßnahmen: Kopien der Daten auf anderen Medien benötigt; Wenn Datenzustand nicht aktuell, müssen die Wirkungen aller seither
bestätigten Transaktionen nachgeführt werden (redo) – Benötigte Zeit: ca. 1 Stunde
Architektur eines Transaktionssystems
Datenmanagement (data manager)
Rücksetzer
(recovery manager)
read, write, lock, release, abort, commit
read, write
...
Stabiler Speicher
Log Instabiler
Speicher
Flüchtiger Speicher read
write
read write
read write
Das Log
Das Log ist eine Repräsentation der Ausführung der Transaktionen.
Im wesentlichen Einträge der Form (Ti, x, v), mit Ti
Transaktionsnummer, x Datenelement, v Wert für jede durchgeführte Schreiboperation.
Einträge totalgeordnet und repräsentieren Ausführungsreihenfolge.
Zusätzlich werden drei Listen unterhalten : – Liste der aktiven Transaktionen (active list)
– Liste der festgeschriebenen Transaktionen (commit list) – Liste der abgebrochenen Transaktionen (abort list)
Ein Eintrag (Ti, x, v) im Log kann entfernt werden, wenn (1) Ti abgebrochen wurde (d.h. alles wiederhergestellt wurde) (2) Ti festgeschrieben wurde und eine andere festgeschriebene
Transaktion v den Wert x überschrieben hat (mit Ti < Tv)
Das Wiederherstellen als Operation muß idempotent sein: Jede Folge unvollständig durchgeführter Wiederherstellungen gefolgt von einer
vollständigen Wiederherstellung muß dasselbe Ergebnis haben wie genau eine vollständige Wiederherstellung.
Wiederherstellungsverfahren
Weitergabe von Änderungen
(Wo stehen festgeschriebene Daten ?): – FORCE Bei Festschreibung werden alle Änderungen der
Transaktion in den stabilen Speicher geschrieben
– NOFORCE Nach Festschreibung einer Transaktion können sich geänderte Daten im flüchtigen Speicher befinden, die noch nicht "gerettet" wurden
Ersetzungsstrategie
(Wo stehen noch nicht festgeschriebene Daten ?): – KEEP Alle Änderungen einer Transaktion werden bis zum
Festschreibungszeitpunkt im flüchtigen Speicher gehalten.
– NOKEEP Der Datenmanager darf auch unbestätigte Daten
aus dem flüchtigen Speicher verdrängen
Wiederherstellungsverfahren
Ziel:
– im flüchtigen Speicher ausschließlich nicht festgeschriebene Daten, – im stabilen Speicher ausschließlich festgeschriebene Daten.
Operationen des Rücksetzers:
– undo: Änderungen unbestätigter Transaktionen im stabilen Speicher müssen rückgängig gemacht werden
– redo: Änderungen bestätigter Transaktionen im flüchtigen Speicher müssen nachgefahren werden.
Je nach der eingesetzten Strategie (keep, force) kann auf redo und/oder undo verzichtet werden.
Bei Keep/Force ist bei der Wiederherstellung nicht viel zu tun, allerdings muß im laufenden Betrieb erheblicher Aufwand getrieben werden.
Bei Nokeep/Noforce ist ein effizienter Normalbetrieb möglich zu Lasten der aufwendigen Wiederherstellung
Verteilte Transaktionen
Verteilte Transaktionen
Bisher haben wir Transaktionen betrachtet, die auf Objekte auf einem einzigen Server (Transaktionssystem) zugreifen (rechts).
Oft jedoch werden die Objekte bzw. Operationen über mehrere Server und damit mehrere Transaktionssysteme verteilt (links).
Zwei Arten von Diensten:
– Nicht-transaktionale Dienste bieten keine Unterstützung für verteilte Transaktionen an, Dienstleistungen werden ohne besondere Garantien erbracht
– Transaktionale Dienste bieten Unterstützung für verteilte Transaktionen an, unterliegen bei entsprechender Abstimmung globalen ACID-Garantien
Beispiel: Buchung einer Reise
– Flug – Hotel
– Bustransfers – Tagesausflüge
Zwei unterschiedliche und unabhängige Datenbanken
Zwei physikalisch getrennte Teile einer Datenbank Geschachtelte Transaktion
Subtransaktion Subtransaktion
Geschachtelte Transaktion Subtransaktion Subtransaktion
Verteilte Transaktionen
Verteilte Transaktionen können wiederum flach (oben) oder
geschachtelt (unten) sein.
Bei einer flachen verteilten Transaktion greift der Client nacheinander auf die beteiligten Server zu.
Bei der Verwendung von Subtransaktionen kann von der Nebenläufigkeit der
verschiedenen Server Gebrauch
X
Y
M
T1 N
T2
T11
Client T
T12 T21 Client
X
Y
Z T
Verteilte Transaktionen: Beispiel
Client
A
B
C T1
T2
T3
T4
T
D X
Y
Z
a.withdraw(10) T = openTransaction
openSubTransaction a.withdraw(10);
openSubTransaction b.withdraw(20);
openSubTransaction c.deposit(10);
openSubTransaction d.deposit(20);
closeTransaction
b.withdraw(20)
c.deposit(10) d.deposit(20)
Beispielarchitektur eines Transaktionssystems
T1
T1 TT22 TT33 Clients TTnn
Koord.
Koord. Koord.Koord. Koord.Koord. Verteilter
TA-Dienst Koord.Koord.
Scheduler Scheduler
Recovery Manager Recovery Manager
Log DB
Scheduler Scheduler
Recovery Manager Recovery Manager
Log DB
Scheduler Scheduler
Recovery Manager Recovery Manager
Log DB
Verteilte TA-Koordinatoren
• Vergabe von TA-Kennungen (TIDs)
• Zuordnung von TIDs zu Operationen
• Koordination von Festschreiben, Rücksetzen und Wiederanlauf Verteilte TA-Koordinatoren
• Vergabe von TA-Kennungen (TIDs)
• Zuordnung von TIDs zu Operationen
• Koordination von Festschreiben, Rücksetzen und Wiederanlauf
Lokale Scheduler
• Lokale Durchführung des 2PS-Prot.
• Lokale Sperrenverwaltung
• Lokale Warteschlangenverwaltung
• Lokale Verklemmungsüberwachung Lokale Scheduler
• Lokale Durchführung des 2PS-Prot.
• Lokale Sperrenverwaltung
• Lokale Warteschlangenverwaltung
• Lokale Verklemmungsüberwachung
Lokale Recovery Manager
• Führung der lokalen Protokolldatei
• Lokales Festschreiben von Transakt.
• Lokales Rücksetzen von Transakt.
• Lokaler Wiederanlauf nach Crash Lokale Recovery Manager
• Führung der lokalen Protokolldatei
• Lokales Festschreiben von Transakt.
• Lokales Rücksetzen von Transakt.
• Lokaler Wiederanlauf nach Crash
Koordination
Zur korrekten Abwicklung der Transaktion müssen die Server ihre Aktionen koordinieren.
Dazu wird für jede Transaktion ein Koordinator (Transaktionsmanager) bestimmt (typischerweise in einem der Server).
Zum Start der Transaktion sendet der Client ein openTransaction() an den Koordinator.
– Dieser startet die Transaktion und liefert eine eindeutige Transaktions-ID (z.B. IP-Nummer + lokale TID) zurück.
– Der Koordinator entscheidet am Ende, ob eine verteilte Transaktion abgebrochen oder korrekt beendet wird.
Er kennt alle Teilnehmer, die wiederum alle ihn kennen.
Neue Teilnehmer melden sich mit der Methode
join(Transaktion,Verweis auf Teilnehmer) an.
Zur Kooperation wird ein Commit-Protokoll (Festschreibungsprotokoll) verwendet.
Globale TID-Erzeugung und -Weiterleitung
Object Request Broker Object Request Broker Client
Client TA-KoordinatorTA-Koordinator
Log
Scheduler Scheduler
Recovery Manager Recovery Manager
Nicht-
Nicht- Transaktionaler
Dienst Transaktionaler
Dienst
Scheduler Scheduler
Recovery Manager Recovery Manager
Client ruft openTransaction()- Methode des TA-Koordinators auf.
Client ruft openTransaction()- Methode des TA-Koordinators auf.
Globale TID-Erzeugung und -Weiterleitung
Object Request Broker Object Request Broker Client
Client TA-KoordinatorTA-Koordinator
Log
Ressource 1 Ressource 1
Scheduler Scheduler
Recovery Manager Recovery Manager
Log DB Nicht-
transaktionaler Dienst Nicht- transaktionaler
Dienst
Transaktionaler Dienst ohne persistenten
Zustand Transaktionaler
Dienst ohne persistenten
Zustand Ressource 2Ressource 2
Scheduler Scheduler
Recovery Manager Recovery Manager
Log DB
TA-Koordinator erzeugt neue TID, kapselt diese als Transaktionsobjekt und protokolliert Existenz der TID.
TA-Koordinator erzeugt neue TID, kapselt diese als Transaktionsobjekt und protokolliert Existenz der TID.
LogLog
Globale TID-Erzeugung und -Weiterleitung
Object Request Broker Object Request Broker Client
Client TA-KoordinatorTA-Koordinator
LogLog
Scheduler Scheduler
Recovery Manager Recovery Manager
Nicht-
Nicht- Transaktionaler
Dienst Transaktionaler
Dienst
Scheduler Scheduler
Recovery Manager Recovery Manager
TA-Koordinator übergibt
Transaktionsobjekt als Kopie an Client, als Seiteneffekt wird dort
ein Request Interceptor („Anforderungs- abfänger“) installiert.
TA-Koordinator übergibt
Transaktionsobjekt als Kopie an Client, als Seiteneffekt wird dort
ein Request Interceptor („Anforderungs- abfänger“) installiert.