Zwei Phase Commit

ist nicht zu empfehlen.

Ich habe schon in den 1990ziger Jahren zu diesem Thema einiges gelesen und auch ausprobiert. So um 1992 hätte ich den Zwei Phasen Commit bei vernetzten MS-DOS Rechner sehr gut gebrauchen können. Das Thema begeisterte mich!

In Projekten nutzten meine Kunden immer eine Grossrechner, auf dem der zentrale Datenbestand auf einer DB2 Instanz lag, da braucht es kein Zwei Phase Commit, dort gibt es ja nur eine Datenbank Instanz, dem ein Commit gesendet wird. Und bei Dialog Programmen, Präsentations- und Fach-, ja sogar bei den auf die Datenbank schreibenden Zugriffsmodulen darf der Programmierer kein Commit setzen, dieses ist einzige Sache des Transaktionsmonitors. In Batch-Programmen habe ich natürlich Commits gesetzt.

Nun war ich bei einem Kunden, und dort gab es einen Programmier-Leitfaden. Unter anderem ist der Zwei Phasen Commit verboten.

Das Verbot ist sehr sinnvoll!

Es sollte, wenn es möglich ist, nur mit einer Datenbank Instanz gearbeitet werden, dann kapselt diese die Transaktionen.

Es gibt Konstellationen, wo leider schreibende Zugriff auf verschiedene Datenbanken notwendig sind. Bei einer festen Kopplung der Systeme bietet sich der Zwei Phase Commit an.

Läuft alles rund, schadet der Zwei Phase Commit nicht, aber braucht man ihn? Der Sinn ist es ja, dass ein Programm einen fachlich bedingten Rollback oder eine technische Komponenten auf Grund von Schwierigkeiten einen technischen Rollback auslösen kann, und dann klar ist, bis wohin zurückgedreht werden muss. 

Vor dem ersten schreibenden Zugriff sollte der Entwickler sicherstellen, dass die Daten passen, es also keinen fachlichen Grund für ein Rollback gibt. Es sind Situationen denkbar, wo in der Zeitspanne zwischen der Prüfung und dem Schreiben etwas passiert, aber diese sind bei guter Programmierung eher eine theoretische Wahrscheinlichkeiten.

Damit sind wir bei den technischen Gründen. Der Ausfall einer Datenbank ist denkbar. Am wahrscheinlichsten ist jedoch, dass Netzwerkverbindungen „sterben“. 

Nun stellen wir uns vor, bei einer Transaktion mit Zwei Phase Commit ist die erste Phase durchgelaufen und das steuernde System sendet die zweite Phase. Genau in dieser Zeitspanne sterben nacheinander, aber in wohl unbekannter Reihenfolge, die Netzwerkverbindungen zu den anderen Systemen.

In den Systemen, die noch die zweite Phase empfangen haben, ist die Transaktion abgeschlossen, bei den anderen ist die Transaktion noch offen und diese Datenbanken wartet auf ihren Timeout, um dann ihr Rollback durchzuführen.

Jetzt ist das Chaos perfekt! Die Transaktion befindet sich in einen undefinierten Zustand, statt „entweder alles oder nichts“ ist jetzt ein „teils/teils“.
Damit hat die geplante Transaktionen einen Zustand wie als wenn keine Transaktionen genutzt werden. 

Der gesamte Aufwand bei der Programmierung, die Lizenzkosten, der Overhead zur Laufzeit für das Zwei Phasen Commit bringen also nichts (oder nur sehr wenig) im Vergleich zum Verzicht auf Transaktionen.

Hoffentlich wird in allen Systemen beim Speichern der „erfasst-am“ Timestamp gesetzt, dann besteht die Möglichkeit der Reparatur. In allen betroffenen Systemen werden die Datensätze, die in der fraglichen Zeitspanne (und natürlich auch davor und danach) geändert wurden, gesammelt. Nun wird geschaut, ob zu einem fachlichen Begriff (zum Beispiel den Konto-Nummern) die Sätze zusammenpassen, also der Zustand der Datenbank wird mit den Vorgaben aus dem Fachkonzept verglichen. Zwischen Fachkonzept und Inhalt der Datenbank liegt bei der Entwicklung viel Arbeit, und bei dieser Reparatur ist der Aufwand vergleichbar. Was innerhalb einer Minute im Online-Betrieb passieren kann, wird einen Entwickler mehrere Tage beschäftigen, wenn er Zugriff auf alle Datenbanken hat. Muss er Daten aus einer entfernten Datenbank, bei einem anderen Unternehmen, anfordern und falls notwendig per Mail oder gar „schriftlich mit drei Durchschlägen“ die Datenreparaturen beantragen, werden aus Tagen schnell Wochen.

Ein kommerzielles Anwendungssystem mit vielen Anwendern (viele meiner Kunden arbeiten mit einer fünfstelligen Anzahl an Online Usern, deren hauptsächlicher „Erwerbszweck“ das Pflegen des Datenbestands ist) kann nicht ohne Transaktionen betrieben werden.

Es gibt aber eine Lösung: Die Systeme werden lose gekoppelt.

Hier gibt es zwei Stufen.

Die einfache Stufe:
Der führende, juristische Bestand, die Golden Source, sende Nachrichten, besser eine asynchrone Transaktion (WebService, SOAP, MQSeries) an einen anderen Bestand, dort werden die Nachrichten aufbereitet und in die Datenbank geschrieben. Es gibt keinen fachlichen Grund, warum die Daten nicht geschrieben werden können, ja, sogar falls die Daten offensichtlich falsch wären, was in der Golden Source steht, muss in die anderen Datenbank übernommen werden. Sollte etwas schiefgehen, kann es nur technische Gründe haben, dann ist der Betreuer des empfangenden Systems für den Wiederanlauf verantwortlich. Bei diesem Wiederanlauf werden die nicht abgeschlossenen Transaktionen automatisch abgearbeitet.

Technisch ist das Vorgehen sehr einfach. 
Kurz vor Abschluss der Transaktion auf dem führenden System wird die asynchrone Transaktion im Asynchronen Transaktion-Monitor geöffnet, es wird die Nachricht geschickt. 
Ist die Transaktion angenommen, gibt der Asynchrone Transaktion-Monitor sein Okay und das führende System kann seine Transaktion mit dem Commit gegen seine Datenbank schliessen. 
Die asynchrone „Tochter-Transaktion“ wird an das empfangene System geschickt, dort verarbeitet.
Nach dem Commit gegenüber der dortigen Datenbank wird mit dem Commit gegenüber dem Asynchronen Transaktion-Monitor die Transaktion geschlossen.
Die Transaktion muss auf dem empfangenen System durchlaufen, eine Information aus der Golden Source muss ja übernommen werden, es gibt keinen fachlichen Grund, die Daten nicht zu speichern.
Geht etwas schief, wird ein technisches Problem vorliegen, es verbleibt eine offene Transaktion im Asynchronen Transaktions-Monitor, die über ein Systemtool an den Administrator gemeldet wird. 

Die Verarbeitung wird zu diesem Zeitpunkt gestoppt, insbesondere wenn nicht komplette Sätze, sondern nur die Differenzen übertragen werden. 

Als Beispiel:
Im Datensatz steht das Feld A bisher auf 'hello' und das Feld B auf 'Ding'.
Die gestoppte Nachricht lautet „Setze Feld A auf 'bye' und Feld B auf 'Auto'“.
Kurz darauf kommt eine Nachricht „Setze Feld A auf 'start'“, die durchlaufen würde.
Dann steht nach dieser Nachricht in der Datenbank Feld A 'start' und Feld B 'Ding'. 
Wird jetzt die gestoppte Nachricht später angenommen, steht in der Datenbank Feld A 'bye' statt 'start'.
Verwerfen wir die Nachricht komplett, steht in Feld B 'Ding' statt 'Auto'.

Umgehen lässt sich das Problem, in dem immer komplette Inhalte als Nachricht gesendet werden und bei Bedarf der aktuelle Zustand angefordert werden kann. Die gestoppte Nachricht würde also ausgesondert und sobald das technische Problem behoben ist, die Golden Source um eine Komplett-Lieferung der betroffenen Daten gebeten.

Die etwas komplexere Stufe: 
Das empfangende System ist (auch) ein juristischer Bestand und darf Nachrichten ablehnen.

Der erste Teil, also das Abarbeiten der Transaktion im führendem System, bleibt fast identisch. 
Die asynchrone Transaktion erhält eine eindeutige ID, und diese ID wird zusammen mit einigen Zusatzinformationen in einer lokalen Verwaltungstabelle nach der Annahme durch den Asynchronen Transaktion Monitor, aber vor dem abschliessenden Commit, gespeichert.

Nach der Verarbeitung durch das empfangene Systeme, egal ob erfolgreich oder auch nicht, wird die gesendete asynchrone Transaktion geschlossen (Commit) und zeitgleich (im Zweifel direkt davor) ein Response, also eine neue asynchrone Transaktion, mit der ID der ursprünglichen Transaktion sowie einer Meldung, also Okay oder dem Fehler, an das ursprüngliche System gesendet. 

Sofern es eine Okay-Meldung ist, setzt das sendende System das „Erfolgreich“ Kennzeichen in seiner Verwaltungstabelle und schliesst die Response-Transaktion.  

Bei einer Fehlermeldung wird die Response-Transaktion nach dem Schreiben der Information in der Verwaltungstabelle geschlossen. Der ursprüngliche Anwender oder ein zentraler Arbeitsplatz bearbeitet dann die ursprüngliche Datenänderung so, dass die neue Transaktion auch vom empfangenden System angenommen wird. 

Bei bekannten Konstellationen ist auch eine automatische Korrektur möglich, wenn zum Beispiel eine Vollmacht zwischen zwei Kunden oder einem Vertrag zu einem Kunden nicht angenommen wird, weil der Bevollmächtigte noch nicht im empfangenen System vorhanden war, Der Bevollmächtigte wird Kunde automatisch gesendet und nach dem Response für die erfolgreich Anlage folgt die Vollmacht.