PostgreSQL Streaming Replication ermöglicht Echtzeit-Replikation von Daten auf Standby-Server. Dies erhöht Verfügbarkeit und ermöglicht Read-Scaling.
Architektur
Master-Standby Setup
Schreibzugriffe → Primary Server (Master)
│
│ WAL Streaming
▼
Standby Server (Replica)
│
▼
Lesezugriffe (Hot Standby)Vorteile
| Feature | Beschreibung | |---------|--------------| | Hochverfügbarkeit | Failover bei Master-Ausfall | | Read Scaling | Lesezugriffe auf Replicas | | Backup | Point-in-Time Recovery | | Disaster Recovery | Geografische Verteilung |
Voraussetzungen
Server-Setup
Primary: 192.168.1.10 (master)
Standby: 192.168.1.11 (replica)
PostgreSQL Version: 16PostgreSQL installieren
# Auf beiden Servern
apt install postgresql-16Primary Server konfigurieren
postgresql.conf
# /etc/postgresql/16/main/postgresql.conf
# Netzwerk
listen_addresses = '*'
port = 5432
# WAL-Einstellungen
wal_level = replica
max_wal_senders = 10
wal_keep_size = 1GB
# Archivierung (optional für PITR)
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/archive/%f'
# Synchrone Replikation (optional)
# synchronous_commit = on
# synchronous_standby_names = 'standby1'pg_hba.conf
# /etc/postgresql/16/main/pg_hba.conf
# Replikations-Verbindungen erlauben
host replication replicator 192.168.1.11/32 scram-sha-256
host replication replicator 192.168.1.0/24 scram-sha-256Replikations-Benutzer erstellen
-- Als postgres-User
sudo -u postgres psql
CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'sicheres_passwort';
-- Prüfen
\du replicatorPrimary neustarten
systemctl restart postgresqlStandby Server einrichten
PostgreSQL stoppen
systemctl stop postgresqlDaten-Verzeichnis leeren
rm -rf /var/lib/postgresql/16/main/*Basis-Backup vom Primary
# Als postgres-User
sudo -u postgres pg_basebackup \
-h 192.168.1.10 \
-U replicator \
-D /var/lib/postgresql/16/main \
-Fp -Xs -P -R
# Optionen:
# -Fp: Plain format
# -Xs: WAL während Backup streamen
# -P: Progress anzeigen
# -R: Standby-Konfiguration erstellenStandby-Signal prüfen
# pg_basebackup mit -R erstellt diese Datei
ls -la /var/lib/postgresql/16/main/standby.signal
# Und postgresql.auto.conf mit Verbindungsinfo
cat /var/lib/postgresql/16/main/postgresql.auto.conf
# primary_conninfo = 'host=192.168.1.10 user=replicator ...'postgresql.conf (Standby)
# /etc/postgresql/16/main/postgresql.conf
# Hot Standby aktivieren
hot_standby = on
# Feedback an Primary
hot_standby_feedback = onStandby starten
systemctl start postgresqlReplikation prüfen
Auf Primary
-- Replikations-Status
SELECT * FROM pg_stat_replication;
-- Detailliert
SELECT
client_addr,
state,
sent_lsn,
write_lsn,
flush_lsn,
replay_lsn,
sync_state
FROM pg_stat_replication;Auf Standby
-- Replikations-Status
SELECT * FROM pg_stat_wal_receiver;
-- Ist Replica?
SELECT pg_is_in_recovery();
-- Sollte 't' (true) zurückgeben
-- Lag prüfen
SELECT
now() - pg_last_xact_replay_timestamp() AS replication_lag;Test
-- Auf Primary: Daten einfügen
CREATE TABLE test_replication (id SERIAL, data TEXT);
INSERT INTO test_replication (data) VALUES ('test data');
-- Auf Standby: Daten sollten erscheinen
SELECT * FROM test_replication;Synchrone Replikation
Primary konfigurieren
# /etc/postgresql/16/main/postgresql.conf
synchronous_commit = on
synchronous_standby_names = 'standby1' # Name des StandbysStandby konfigurieren
# /etc/postgresql/16/main/postgresql.auto.conf
primary_conninfo = 'host=192.168.1.10 user=replicator password=xxx application_name=standby1'Prüfen
-- Auf Primary
SELECT application_name, sync_state FROM pg_stat_replication;
-- sync_state sollte 'sync' seinManueller Failover
Standby zum Primary promoten
# Auf Standby
sudo -u postgres pg_ctl promote -D /var/lib/postgresql/16/main
# Oder
sudo -u postgres psql -c "SELECT pg_promote();"Status prüfen
-- Sollte 'f' (false) sein nach Promotion
SELECT pg_is_in_recovery();Alten Primary als Standby einrichten
# 1. PostgreSQL stoppen
systemctl stop postgresql
# 2. Daten-Verzeichnis löschen
rm -rf /var/lib/postgresql/16/main/*
# 3. Basis-Backup vom neuen Primary
sudo -u postgres pg_basebackup \
-h 192.168.1.11 \
-U replicator \
-D /var/lib/postgresql/16/main \
-Fp -Xs -P -R
# 4. Starten
systemctl start postgresqlAutomatischer Failover mit Patroni
Installation
apt install patroni python3-etcdKonfiguration
# /etc/patroni/patroni.yml
scope: postgres-cluster
name: node1
restapi:
listen: 0.0.0.0:8008
connect_address: 192.168.1.10:8008
etcd:
hosts: 192.168.1.20:2379,192.168.1.21:2379,192.168.1.22:2379
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
parameters:
max_connections: 100
shared_buffers: 256MB
initdb:
- encoding: UTF8
- data-checksums
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.1.10:5432
data_dir: /var/lib/postgresql/16/main
authentication:
replication:
username: replicator
password: sicheres_passwort
superuser:
username: postgres
password: postgres_passwortService
systemctl enable patroni
systemctl start patroni
# Status
patronictl -c /etc/patroni/patroni.yml listpg_rewind für schnellen Resync
Nach Failover
# Alter Primary als Standby
sudo -u postgres pg_rewind \
--target-pgdata=/var/lib/postgresql/16/main \
--source-server='host=192.168.1.11 user=postgres dbname=postgres'Voraussetzungen
# Auf allen Servern
wal_log_hints = on
# Oder
# initdb mit --data-checksumsMonitoring
Replikations-Lag
-- Auf Primary
SELECT
application_name,
client_addr,
state,
pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn) AS sent_lag,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS replay_lag
FROM pg_stat_replication;Monitoring-Skript
#!/bin/bash
# check_replication.sh
LAG=$(sudo -u postgres psql -t -c "
SELECT COALESCE(
EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp())),
0
)::INT
")
if [ "$LAG" -gt 300 ]; then
echo "CRITICAL: Replication lag is ${LAG} seconds"
exit 2
elif [ "$LAG" -gt 60 ]; then
echo "WARNING: Replication lag is ${LAG} seconds"
exit 1
else
echo "OK: Replication lag is ${LAG} seconds"
exit 0
fiPrometheus
-- pg_stat_replication für Prometheus exportieren
SELECT
'pg_replication_lag_seconds{application_name="' || application_name || '"} ' ||
COALESCE(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn), 0)
FROM pg_stat_replication;Read Replicas nutzen
Connection Pooling mit PgBouncer
# /etc/pgbouncer/pgbouncer.ini
[databases]
myapp_primary = host=192.168.1.10 dbname=myapp
myapp_replica = host=192.168.1.11 dbname=myapp
[pgbouncer]
listen_addr = *
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 1000
default_pool_size = 20Anwendungs-Konfiguration
# Django settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'HOST': '192.168.1.10', # Primary für Schreiben
'NAME': 'myapp',
},
'replica': {
'ENGINE': 'django.db.backends.postgresql',
'HOST': '192.168.1.11', # Replica für Lesen
'NAME': 'myapp',
}
}Zusammenfassung
| Befehl | Funktion | |--------|----------| | pg_basebackup | Basis-Backup erstellen | | pg_ctl promote | Standby zum Primary | | pg_rewind | Schneller Resync |
| Parameter | Beschreibung | |-----------|--------------| | wal_level | replica für Streaming | | max_wal_senders | Max. Replikations-Verbindungen | | hot_standby | Lesezugriff auf Standby | | synchronous_commit | Synchrone Replikation |
| View | Information | |------|-------------| | pg_stat_replication | Status auf Primary | | pg_stat_wal_receiver | Status auf Standby | | pg_is_in_recovery() | Replica-Check |
Fazit
PostgreSQL Streaming Replication ist robust und performant. Hot Standby ermöglicht Lesezugriffe auf Replicas. Für automatischen Failover empfiehlt sich Patroni mit etcd. Synchrone Replikation garantiert Datenkonsistenz bei Failover. Read Replicas mit PgBouncer verbessern die Skalierbarkeit. Die native Replikation ist für die meisten Hochverfügbarkeits-Anforderungen ausreichend.