PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Verwenden von Zwei-Phasen-Commits auf Postgres

Ich glaube, Sie haben PREPARE TRANSACTION falsch verstanden .

Diese Anweisung beendet die Arbeit an der Transaktion, dh sie sollte nach ausgegeben werden die ganze Arbeit ist getan. Die Idee ist, dass PREPARE TRANSACTION tut alles, was während eines Commit möglicherweise fehlschlagen könnte, außer dem Commit selbst. Das soll garantieren, dass ein nachfolgendes COMMIT PREPARED kann nicht fehlschlagen.

Die Idee ist, dass die Verarbeitung wie folgt ist:

  • Führen Sie START TRANSACTION aus auf allen an der verteilten Transaktion beteiligten Datenbanken.

  • Mach die ganze Arbeit. Wenn es Fehler gibt, ROLLBACK alle Transaktionen.

  • Führen Sie PREPARE TRANSACTION aus auf allen Datenbanken. Wenn das irgendwo fehlschlägt, führen Sie ROLLBACK PREPARED aus auf der Datenbank, wo die Transaktion bereits vorbereitet wurde und ROLLBACK auf den anderen.

  • Einmal PREPARE TRANSACTION überall erfolgreich war, führen Sie COMMIT PREPARED aus auf allen beteiligten Datenbanken.

So können Sie über mehrere Datenbanken hinweg „alles oder nichts“ garantieren.

Eine wichtige Komponente hier, die ich nicht erwähnt habe, ist der verteilte Transaktionsmanager . Es ist ein Stück Software, das sich ständig merkt, wo sich die Verarbeitung des obigen Algorithmus gerade befindet, damit es nach einem Absturz aufräumen oder mit dem Commit fortfahren kann.

Ohne einen verteilten Transaktionsmanager ist das zweiphasige Commit nicht viel wert, und es ist sogar gefährlich:Wenn Transaktionen in der „vorbereiteten“ Phase stecken bleiben, aber noch nicht festgeschrieben sind, halten sie weiterhin Sperren und (im Fall von PostgreSQL) blockieren die Autovacuum-Arbeit sogar bei Serverneustarts , da solche Transaktionen persistent sein müssen.

Das ist schwer richtig zu machen.