Diese Anleitung richtet sich an diejenigen, die mit wenig Aufwand eine PostgreSQL-Datenbank zur Verfügung stellen möchten, die auch beim Ausfall eines Servers ihre Daten nicht verliert und eine Art "Hochverfügbarkeit für Arme" anbietet.
Es existieren bereits Systeme, die eine "echte" Hochverfügbarkeit bietet, erzeugen aber ungleich mehr Aufwand und Systemkenntnisse. Wer also "echte" HA sucht, die auch Standortübergreifend funktioniert, dem sei zu "Patroni" geraten, oder aber gleich ein Cluster mit Corosync und Pacemaker
In diesem Beispiel wird ein Debian bzw. Ubuntu-System ausgegangen, das in 2 Instanzen bereit steht, die sich ihrerseits auch in demselben IP-Subnetz befinden. In dieser ersten Variante wird ein manuelles Failover vorausgesetzt. Wenn ein Server ausfällt, muss manuell der Cluster wieder in Synchronisation gebracht werden. Die meisten der zitierten Befehle und Aktionen erfolgen als User "root" (unter Ubuntu: "sudo- i"), wird ein anderer user verwendet, wird es explizit erwähnt!
1. Server-Installation
Zunächst werden zwei reale oder virtuelle Server mit dem Betriebssytem versehen. Hier wird nur eine minimale Installation notwendig, die "Server-Variante" des Ubuntu Linux ist völlig ausreichend. Wichtig ist die SecureShell und die Datenbank und die zugehörigen Tools. Der Befehl dazu:
apt-get install openssh-server openssh-client postgresql postgresql-client
2. Netzwerkkonfiguration
In diesem Beispiel werden die beiden Netz-Adressen manuell eingetragen. Das zugehörige Subnetz sei hier 192.168.10.0/24, Default Gateway ist 192.168.10.1. Namensserver sind in diesem speziellen Beispiel ohne Relevanz, weil wir uns auf die feste Konfiguration der Server verlassen wollen. In großen Umgebungen kann allerdings schwerlich auf DHCP und DNS verzichtet werden, doch behandeln wir hier nur eine minimal-Konfiguration. der erste Server sei hier pg-cluster1, der zweite pg-cluster2. Die Datei /etc/hosts bekommt daher diese beiden zusätzlichen Einträge:
192.168.10.11 pg-cluster1 192.168.10.12 pg-cluster2
3. Konfiguration des Master-Servers (pg-cluster1)
Für den Anfang wird der erste Rechner pg-cluster1 als Masterserver auserkoren, dager wird an diesem die Konfiguration begonnen:
Die Datenbank wird gestartet und der DB-Superuser konfiguriert. Der Einfachheit halber wird der User postgres mit einem einfachen Passwort ("admin") versehen und auch zur Replikation verwendet.
VORSICHT: DIESE EINSTELLUNG AUF KEINEN FALL FUER PRODUKTIVZWECKE VERWENDEN!!!!!
Der User postgres sollte gar nicht verwendet werden, sondern ein selbst erstellter user mit Superuser-Rechten, sowie ein dedizierter Replikationsuser.
template1=# alter user postgres with password 'admin'; ALTER ROLE template1=#
Zum Test wird an dieser Stelle eine Datenbank angelegt, damit die Eigenschaften des Clusters und der Replikation überprüft werden können.
postgres@pg-cluster1:~$ createdb db01 postgres@pg-cluster1:~$ psql db01 psql (9.5.6) Type "help" for help. db01=# create table meintest(uid serial, description varchar(20)); CREATE TABLE db01=# insert into meintest (description) values ('Erster'); INSERT 0 1 db01=# insert into meintest (description) values ('Zweiter'); INSERT 0 1 db01=# select * from meintest; uid | description -----+------------- 1 | Erster 2 | Zweiter (2 rows)
Unter Root-Berechtigung wird nun die Haupt-Konfigurationsdatei /etc/postgresql/9.5/main/postgresql.conf verändert. Bitte ersetzen Sie die den Teil das Pfades, der die Versionsnummer darstellt (hier: 9.5) mit der bei Ihnen eingesetzten PostgreSQL-Version. In dieser Datei finden Sie bereits eine ganze Reihe Werte, die bereits durch die Installation gesetzt wurden. Die zu ändernden Zeilen sind diese:
listen_addresses = '*' wal_level = logical max_wal_senders = 10 hot_standby = on wal_keep_segments = 8 hot_standby = on
den Rest belassen Sie so, wie Sie sie vorfinden!
Analog wird die Datei /etc/postgresql/9.5/main/pg_hba.conf angepasst, in dem diese beiden Zeilen hinzu gefügt werden:
host replication postgres 192.168.10.12/32 md5 host replication postgres 192.168.10.11/32 md5
Jetzt wird es zeit für einen Neustart der Datenbank:
systemctl restart postgresql
Die Datenbank sollte danach wieder vollständig verfügbar sein.
3. Konfiguration des Slave-Servers (pg-cluster2)
Auf dem Slave wird zunächst die vorhandene Datenbank gelöscht und mit einem Replikat des Master-Servers ersetzt. Zuerst wird die Datenbank gestoppt
systemctl stop postgresql
Ändern Sie dazu die Felder der /etc/postgresql/9.5/main/postgresql.conf wie beim Master-Server:
listen_addresses = '*' wal_level = logical max_wal_senders = 3 wal_keep_segments = 8 hot_standby = on
Auch die /etc/postgresql/9.5/main/pg_hba.conf wird ergänzt:
host replication postgres 192.168.10.11/32 md5 host replication postgres 192.168.10.12/32 md5
Dann erzeugen Sie als user "postgres" die Replikation. Zunächst werden alle Dateien der alten, nicht mehr benötigten Datenbank gelöscht:
rm -r var/lib/postgresql/9.5/main/*
Die gelöschten Dateien werden mit einem Replikat des Masterservers pg-cluster1 ersetzt. Dazu wird dieser Befehl verwendet:
pg_basebackup -D /var/lib/postgresql/9.5/main -h pg-cluster1 --checkpoint=fast --xlog-method=stream -R
Das Passwort ist hier 'admin'!
Hier wird automatisch die Datei recovery.conf erzeugt, die die Zugangsdaten zum Master-Server enthält. Wird dann der Postgres-Server wieder gestartet, begibt er sich automatisch in den Recovery-Modus, und ist auch durch das gesetzte hot_standby=on für den ReadOnly-Zugriff bereit. Die Datenbank wird wieder als User "root" gestartet:
systemctl start postgresql
Test: Auf dem Master wird eine Tabelle verändert:
insert into meintest (description) values ('Zweiter');
Auf dem Slave wird die Tabelle gelesen und die neue Zeile bereits angezeigt:
select * from meintest;
uid | description
-----+-------------
1 | Erster
2 | Zweiter
Wird eine Schreib-Operation auf dem Slave versucht, wird sie abgewiesen:
db01=# update meintest set description='Fuenf' where uid=5; ERROR: cannot execute UPDATE in a read-only transaction
HAVARIE 1: Master fällt aus.
Auf dem alten Slave pg-cluster2 als user postgres
ausführen:
/usr/lib/postgresql/9.5/bin/pg_ctl -D/var/lib/postgresql/9.5/main promote
Fertig. Hier ist kein Restart nötig!!! Der Server ist ab sofort im RW-Modus und enthält nun die aktive Datenbank! Der alte Master (pg-cluster1) muss nun zum neuen Slave gemacht werden. Zunächst muss der alte Server irgendwie aus einem Backup gezogen, oder manuell nach obigen Schema nachgebaut werden. Im ersteren Fall darf der Server aber nicht "einfach so gestartet werden, sondern die Daten vom neuen Master übernommen werden. Das erfolgt mit diesen Schritten:
a)Sicherstellen das die DB nicht läuft:
systemctl stop postgresql
Weitere Befehle werden als User postgres ausgeführt (su - postgres):
b) Verzeichnis entsorgen
rm -r /var/lib/postgresql/9.5/main/*
c) Die Dateien /etc/postgresql/9.5/main/postgresql.conf und /etc/postgresql/9.5/main/pg_hba.conf nach obigen Vorbild kontrollieren und ggf. ändern.
Dateien replizieren:
pg_basebackup -D /var/lib/postgresql/9.5/main -h pg-cluster2 --checkpoint=fast --xlog-method=stream -R
Das Passwort ist hier wieder 'admin'!
d) Als User root wird die Datenbank wieder gestartet:
systemctl start postgresql
Damit ist der Server wieder vollständig.
HAVARIE 2: Slave fällt aus.
An dieser Stelle wird der Zustand des Clusters nicht verändert. Der Slave wird mit den obigen Befehlen unter Postgres wieder hergestellt:
rm -r /var/lib/postgresql/9.5/main/* pg_basebackup -D /var/lib/postgresql/9.5/main -h pg-cluster1 --checkpoint=fast -x -P -R
Automatisches Verfahren
Das Verfahren für einen automatischen Wechsel des Master/Slave-Zustandes kann beim Starten geschehen und lässt sich im Pseudocode folgendermaßen beschreiben:
if [remote_db_avaliable] then if [local_db_is_slave] then if [remote_db_is_master] then start postgres else if [Quorum_avaliable] then Stop remote DB (STONITH) Promote localDB start postgres else Stop remote DB STOP DB fi fi else if [remote_db_is_master] then Demote local DB start postgres else start postgres fi fi else if [Quorum_avaliable] then if [local_db_is_slave] then Promote local DB start postgres else start postgres fi else STOP DB fi fi
Eine Abfrage auf den Master-/Slave-Zustand kann durch eine SQL-Abreage geschehen:
select pg_is_in_recovery(); -> "f" (false) ==> Master -> "t" (true) ==> Slave
Alternativ kann per Shell Befehl daif Existenz der Datei recovery.con getestet werden:
test -f /etc/postgresql/9.5/main/recovery.conf -> false ==> Master -> true ==> Slave
Promote zum Master:
/usr/lib/postgresql/9.5/bin/pg_ctl -D/var/lib/postgresql/9.5/main promote
Demote zum Slave:
rm -r /var/lib/postgresql/9.5/main/* pg_basebackup -D /var/lib/postgresql/9.5/main -h pg-cluster1 --checkpoint=fast -x -P -R