Aus Linux-Magazin 04/2017

PostgreSQL-Replikation: Ein Statusbericht

© Vit Paroulek, 123RF

Hochverfügbarkeit, Replikation und Skalierung sind in der Datenbankwelt alltägliche Notwendigkeiten. Welche Features bietet PostgreSQL in diesem Zusammenhang und was taugen sie?

Wer sich professionell als PostgreSQL-Consultant [1] mit dem Thema Replikation beschäftigt, gewinnt den Eindruck, dass Kunden und Kollegen nur verteilte, synchrone Multimaster-Replikation als wahre Replication ansehen. Aber ist das wirklich so?

Synchron vs. asynchron

Generell lässt sich die Replikation in unterschiedlicher Weise einteilen, zum Beispiel danach, ob sie synchron oder asynchron erfolgt (Abbildung 1). Bei synchroner Replikation gilt eine Transaktion erst dann als abgeschlossen, wenn sie von der Gegenstelle bestätigt ist. Der Vorteil – besonders bei einem Crash – ist, dass die Daten auf mindestens zwei Systemen angekommen sein müssen.

Abbildung 1: Bei der asynchronen Replikation ergibt sich ein Zeitversatz beim Ausführen der Transaktionen.

Abbildung 1: Bei der asynchronen Replikation ergibt sich ein Zeitversatz beim Ausführen der Transaktionen.

Speziell im Bereich Replikation gibt es aber wenige Dinge, die nur Vorteile haben – so ist es auch hier. Der Nachteil von synchroner Replikation ist, dass die Daten unbedingt auf mindestens zwei Systeme zu schreiben sind. Der Vorteil ist also gleichzeitig ein Nachteil, denn die doppelten Schreiboperationen kosten selbstverständlich Zeit.

Single- und Multimaster

Die Unterscheidung zwischen Singlemaster und Multimaster ist ebenfalls wichtig. Wenn sich viele Anwender für Multimaster entscheiden, dann weil sie damit die Leselast verteilen können. Aber werden Schreibzugriffe auch schneller? Natürlich nicht: Beide Maschinen müssen alle Daten schreiben. Ein anderes Argument, das viele oft ins Feld führen, ist die höhere Verfügbarkeit.

Das ist allerdings etwas komplizierter: Wenn zwei Maschinen die gleichen Daten haben müssen – wegen der synchronen Replikation –, wird es dann einfacher, auf eine Maschine zu verzichten? Eher nicht. Wenn aber die beiden Maschinen asynchron sind, bedeutet dies, dass sie zu einem Zeitpunkt verschiedene Daten haben können. Es kann dann also sein, dass Konflikte entstehen, die zu lösen sind. Meist geht das nur, indem eine der beiden Transaktionen ex post (also nach dem Commit) zurückrollt.

Ein praktisches Beispiel: Angenommen es befinden sich 100 Euro auf einem Konto und zwei Leute wollen davon 90 Euro abheben. Ihre Transaktionen landen auf unterschiedlichen Maschinen im asynchronen Cluster. Beide Rechner buchen die 90 Euro ab und behalten 10. Beide committen die Transaktion und tauschen sich erst danach darüber aus. Erst jetzt wird beiden klar, dass das Geld doppelt ausgegeben wurde, und beide nehmen die Transaktion zurück.

Die Möglichkeit von Konflikten ist bei asynchroner Multimaster-Replikation immer in Betracht zu ziehen. Die Server bleiben zwar “eventually consistent”, aber eben nicht immer und zu jedem Zeitpunkt. Es gibt Szenarien, in denen das kein Problem ist, weil kaum Konflikte auftreten können.

Man nehme etwa einen weltweiten Flugzeugvertrieb. Jemand will in Japan einen Flieger kaufen. Wie wahrscheinlich wäre es, dass ein zweiter Kunde in Deutschland sich in derselben Sekunde für dasselbe Flugzeug entscheidet? Die Wahrscheinlichkeit ist nahe null. Asynchrone Multimaster-Replikation ergibt also Sinn, wenn die beteiligten Partner geografisch verteilt sind und ein Konflikt de facto nicht auftreten kann.

Synchrone Multimaster-Replikation ist dagegen in der Regel unter keinen Umständen sinnvoll. Denn damit geht die Performance derart in den Keller, dass nur noch sehr wenige Transaktionen pro Sekunde möglich sind. Das Problem dabei: Es ist die Zustellreihenfolge von Netzwerkpaketen zu garantieren, um nicht in Deadlocks zu geraten – nachteilig für die Latenz.

Wenn es um Verfügbarkeit geht: Keep it simple. Wenn es um Leseperformance geht, ist synchrone oder asynchrone Singlemaster-Replikation das Mittel der Wahl. Wenn der Admin die Schreibperformance skalieren will, muss er die Daten im Cluster verteilen (sharden, horizontal partitionieren). Steht die Verfügbarkeit alleine im Vordergrund, macht er sich mit Multimaster-Replikation an einem Standort keine Freude, weil er dann Kompromisse schließen muss, die eigentlich unnötig sind. Es gilt die Regel: Je einfacher das Setup ist, umso leichter wird es.

Das Transaction-Log

Wer sich mit dem Transaction-Log der Datenbank nicht auskennt, der wird auch die PostgreSQL-Replikation nicht verstehen. Generell ist es so, dass PostgreSQL im Gegensatz zu Datenbanken, die das ISAM-Zugriffsverfahren (Index Sequential Access Method) nutzen, nicht direkt in ein Datafile schreiben darf. Jede Änderung muss es zuerst im Transaction-Log protokollieren. Der Grund leuchtet ein: Ein Rechner kann zu jedem Zeitpunkt abstürzen. Passiert das genau dann, wenn die Datenbank in ihr Datafile schreibt, führt das zu einem korrupten File mit unvollständigen Daten.

Die PostgreSQL-Lösung für dieses Problem heißt WAL (Write Ahead Log). Die Idee ist, alle Änderungen erst zu protokollieren, bevor sie in das Datafile gelangen. Das ähnelt im Prinzip dem, was moderne Journaling-Filesysteme tun. In PostgreSQL beschreibt das Transaction-Log, welche binären Änderungen im Falle eines Recovery vorzunehmen sind.

Das Transaction-Log enthält kein SQL – es geht nur um Änderungen in den Datafiles. Darum eignet es sich auch hervorragend für Dinge wie Replikation. Wenn auf Basis des Transaction-Logs ein Slave erzeugt wird, ist er quasi binärgleich.

Streaming Replication

Die einfachste und wartungsärmste Form der Datendopplung ist die so genannte Streaming Replication. Dabei wird zuerst ein Backup der Datenbankinstanz angefertigt. Änderungen nach Abschluss des Backups zieht der Admin dann mit Hilfe des Transaction-Logs nach. Wer ein solches Setup aufsetzen will, editiert die Datei »postgresql.conf« auf dem Master so, dass sie die folgenden Einträge enthält:

wal_level = replica
max_wal_senders = 3
hot_standby = on

Danach muss der Admin in der Datei »pg_hab.conf« ergänzen:

host    replication     postgres     192.168.0.45/32         md5

Dazu trägt er einfach die IP-Adresse des Slave ein (in diesem Fall »192.168.0.45«) und startet den Master neu. Anschließend kommt der Slave an die Reihe. Dort installiert der Admin PostgreSQL und schafft einen Platz für die Daten:

mkdir /data
chmod 700 data

Dann kann das initiale Backup vom Slave aus loslaufen:

pg_basebackup -D /data -h IP_des_Master --checkpoint=fast --xlog-method=stream -R

Sobald die Daten kopiert sind, sollte der Slave starten. Die Option »-R« generiert bereits die Konfigurationsdatei für den Slave. Sobald er läuft, ist der Slave als Read-only-Maschine einsetzbar. Selbstverständlich lassen sich beliebig viele Slaves erzeugen, auch sternförmige Replikation ist möglich. Im Standardfall ist diese Replikation vom Typ Singlemaster und asynchron.

Synchrone Replikation

Wer synchrone Replikation benötigt, kann das ebenfalls sehr leicht konfigurieren. Er stellt dabei am Master in der »postgresql.conf« die Option »synchronous_standby_names« ein (beispielsweise auf »synchronous_standby_names = node1, node2, node3«) und fügt in der Datei »recovery.conf« des Slave einfach im Abschnitt »primary_conninfo« hinzu: »application_name=node1«.

Node1 wird in diesem Fall zu einem synchron replizierten Knoten. Im vorliegenden Beispiel ist wichtig, dass für »node1« synchron das Default Setting ist – PostgreSQL bietet allerdings die Möglichkeit, für jede einzelne Transaktion zu entscheiden, wie sie zu replizieren ist. Das ist nützlich, um nicht für jede Transaktion den Overhead eines synchronen Commit auf sich nehmen zu müssen.

Um die Güte (Durability) einer Transaktion festzulegen, ist auf Session-Ebene die Option »synchronous_commit« auf einen dieser fünf Werte einstellbar:

  • »remote_apply«: Eine Transaktion gilt, wenn sie auf beiden Systemen geschrieben und am Slave auch sichtbar ist. Wichtig für Load Balancing.
  • »on«: Eine Transaktion wird auf beiden Systemen geflusht, sie muss aber noch nicht für andere Reads sichtbar sein. Man kann also etwa synchron replizieren, obwohl der Slave sechs Stunden alte Daten anzeigt.
  • »remote_write«: Die Transaktion wird auf dem Master geflusht, aber auf dem Standby-System nur an den Kernel weitergegeben (ohne Flush). Das macht die Transaktion schneller. Der Nutzer geht davon aus, dass nicht beide Storage-Systeme gleichzeitig sterben.
  • »local«: Flush auf dem Master, aber kein Feedback vom Slave nötig (asynchron).
  • »off«: In diesem Fall wird am Master verzögert geflusht und die Replikation asynchron erzeugt. Die Datenbank garantiert zur jedem Zeitpunkt Integrität – darf aber im Fehlerfall einige Millisekunden lang Daten verlieren. Die Idee ist, kurze Transaktionen zu beschleunigen.

Folgendes Beispiel zeigt, wie User die Durability einer Transaktion beeinflussen:

BEGIN;
SET synchronous_commit TO remote_write;
INSERT INTO tab VALUES [...]
COMMIT;

Die Durability lässt sich für jede Transaktion einzeln einstellen.

PostgreSQL 9.6 und 10.0

In vielen Fällen will der Anwender einen Cluster nicht auf zwei Knoten beschränken. Daher erlaubt es PostgreSQL, beliebig viele Slaves zu managen. Dabei ist es auch möglich, die Anzahl der synchronen Slaves festzulegen. Wer beispielsweise zehn Slaves hat, kann PostgreSQL mit einer einfachen Syntax anweisen, sieben davon synchron zu halten. Ein Commit erfolgt also erst, wenn ausreichend viele Maschinen ihr Okay gegeben haben und die Daten daher sicher sind.

Es ist mit einer Konfigurationszeile möglich, Maschinen auf mehreren Kontinenten synchron zu halten und zu managen. Dabei ist aber zu bedenken: Die Grenzen der Physik gelten weiterhin – niemand kann Daten synchron um den halben Erdball replizieren und davon ausgehen, dass dies keine Auswirkungen auf die Geschwindigkeit seiner Schreibtransaktionen hat. Es ist immer ein Trade-off zwischen Durability und Performance.

Bidirektionale Replikation

In manchen Fällen kommt der Admin um bidirektionale Replikation nicht herum. Vor einigen Jahren haben die PostgreSQL-Entwickler so genanntes Logical Decoding implementiert. Damit ist es möglich, das Transaction-Log mit Hilfe eines Plugins zu dekodieren und die Inhalte wieder in SQL-Statements zu verwenden.

Angenommen ein Benutzer setzt folgendes SQL-Statement ab:

DELETE FROM data WHERE id < 4;

In dem Fall würde die Dekodierung des Transaction-Logs diesen Output liefern:

DELETE FROM data WHERE id = 1;
DELETE FROM data WHERE id = 2;
DELETE FROM data WHERE id = 3;

Der so entstandene Datenstrom lässt sich dann auf einem Subscriber wieder einspielen.

In PostgreSQL wird es künftig möglich sein, diesen Datenstrom zu verwenden, um Slaves zu synchronisieren und so fast Downtime-freie Updates zu liefern. In kommenden Versionen wird auch bidirektionale Replikation damit machbar. Derzeit ist bidirektionale asynchrone Replikation nur mit einem Tool namens BDR möglich, das als Package zusätzlich zu installieren ist.

Nun ein Beispiel, bei dem bidirektionale Replikation Sinn ergibt: Angenommen eine Versicherung betreibt Filialen in den USA und Europa. In diesem Fall ist es möglich, dass die Datenleitung ausfällt – es ist aber sehr unwahrscheinlich, dass dasselbe Auto in den USA und in Europa zur selben Zeit versichert wird. Die Konfliktwahrscheinlichkeit ist niedrig.

Die Königsklasse: Automatisches Failover

PostgreSQL ist eine sehr moderne Datenbank und bietet speziell im Replikationsumfeld zahlreiche Features. Allein das Buch “PostgreSQL Replication” von Packt Publishing ist fast 400 Seiten stark und dennoch bei Weitem nicht vollständig. Dennoch: PostgreSQL selbst ist keine Clustersoftware – Dinge wie automatisches Failover und Verwandtes sind nicht in PostgreSQL implementiert. Hierfür sind externe Tools nötig.

Eines der bekanntesten ist Zalandos Patroni [2]. Das Tool verwendet den so genannten Paxos-Algorithmus, um festzustellen, wer im Cluster welche Rolle innehaben soll. Erkennt Patroni auf Basis des Konsensalgorithmus, dass ein Failover erfolgen muss, triggert es die nötigen Operationen an. Die Konfiguration ist relativ einfach (Abbildung 2). Zu beachten ist, dass Patroni zwar die Services startet und stoppt, jedoch keine IP-Adressen managt. Eine Applikation, die von außen auf den Cluster zugreift, muss sich im Fehlerfall also zu einer anderen IP-Adresse verbinden.

Abbildung 2: Eine Streaming Replication vom Master zum Slave, bei der Patroni mit Hilfe eines Quorums die Rollenverteilung &uuml;bernimmt.

Abbildung 2: Eine Streaming Replication vom Master zum Slave, bei der Patroni mit Hilfe eines Quorums die Rollenverteilung übernimmt.

Auch dafür gibt es Lösungen. PostgreSQL und Patroni lassen sich etwa mit Consul [3] kombinieren, um bei einem Failover direkt die DNS-Einträge zu ändern. Die Firma Cybertec [4] will in Kürze eine frei verfügbare Lösung anbieten, die Failover samt Replikation automatisiert.

Entscheidungshilfen

Wer vor der Situation steht, eine passende Lösung für sein Problem zu finden, sollte zuerst klären, was er wirklich erreichen will: Geht es um Verfügbarkeit? Geht es um Skalierung? Oder geht es darum, ein geografisch verteiltes System zu schaffen? Wem es um Verfügbarkeit geht, der sollte auf einfache Master-Slave-Replikation setzen. Wem Leseskalierung am wichtigsten ist, der sollte erst seine Workloads auf fehlende Indexe und so weiter untersuchen – und dann noch einmal nachdenken.

In vielen Fällen lassen fehlende Indexe den Workload größer erscheinen, als er wirklich ist. Ein moderner Datenbankserver kann Hunderttausende Abfragen pro Sekunden abwickeln – es ist nötig, vor einer Serverskalierung zu prüfen, ob die Infrastruktur nicht einfach nur schlecht genutzt wird. Wenn die Leselast trotzdem zu hoch ist, lässt sich auf Streaming Replication zurückgreifen. Ist das System global verteilt, kann sich eine asynchrone Multimaster-Lösung anbieten – dafür müssen die Konfliktwahrscheinlichkeiten aber gering sein.

Im PostgreSQL-Umfeld überschlagen sich zurzeit die Ereignisse. Kaum ein Monat vergeht, ohne dass neue Funktionen dazukommen. In allen Bereichen sind substanzielle Verbesserungen zu erwarten, die heute teils noch gar nicht absehbar sind. Es zahlt sich also aus, sich weiter zu informieren.

Der Autor

Hans-Jürgen Schönig ist CEO der Cybertec Schönig & Schönig GmbH, einer Firma, die seit fast 20 Jahren professionellen 24×7-Support, Training, Consulting, Hochverfügbarkeit und Performance Tuning für PostgreSQL anbietet. Er hat zahlreiche Bücher zum Thema geschrieben und arbeitet mit Kunden weltweit.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 4 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben