Ich habe mit Postgres 9.5.4 und mit 9.6 auf Centos 6.8 versucht synchrone
Replikation zu betreiben.
Im prinzip funktioniert die synchrone Replication solange der Slave läuft, aber wenn Slave gestoppt wird, bleibt das
Statement am server stecken,
erst nach control c wird es mit folgender meldung beendet:
Das wal_sender_timeout sollte doch dazu dasein, dass der Master alleine weitermacht, wenn der Slave nach dieser Zeit nicht erreichbar ist,
oder ist das anders?
indb=# update “Subscribers” set “AccountBalance” = “AccountBalance” + 1
where “MSISDN” = 4367761000003::text;
WARNING: L_047 SBSTRIGG 232077610000052 CHG=-1.00000 entry stati=2 2
oldBal=23.81000 newBal=24.81000 BSstate=16 RchTimes=2014-07-21
11:25:07.840565 2014-07-21 11:25:07.840565
NOTICE: L_099 SBSTRIGG 232077610000052 check InsertLowBalanceQueue:
options=0 old.accbal=23.81000 new.accbal=24.81000 lowballimit=0.00000
lowbalreached:0
^CCancel request sent
WARNING: canceling wait for synchronous replication due to user request
DETAIL: The transaction has already committed locally, but might not have
been replicated to the standby.
UPDATE 1
Das wal_sender_timeout steht auf 1s:
indb=# show wal_sender_timeout;
wal_sender_timeout
1s
(1 row)
Das master postgresql.conf unterscheidet sich vom default durch:
listen_addresses = ‘’
port = 5034
wal_level = replica
archive_mode = on
archive_command = ‘cp -i %p /export/test_wal/indb_test1/%f </dev/null’
max_wal_senders = 3
wal_keep_segments = 400
wal_sender_timeout = 1s
max_replication_slots = 5
synchronous_standby_names = '’
log_filename = ‘postgresql-%Y-%m-%d.log’
log_min_duration_statement = 0
log_connections = on
log_disconnections = on
log_lock_waits = on
Warum greift das wal_sender_timeout = 1s nicht ?
Ich würde erwarten, dass nach 1 sec (wenn slave solange nicht antwortet)
die Replikation beendet wird
und der Master weiter laufen kann (also ohne Slave alle update,inserts
durchführt)
Synchrone Replikation macht nur Sinn mit mind. 2 Standbys (oder 1 Standby und 1 Barman-Server in Version 2.0 aufwärts). wal_sender_timeout ist dazu da, einen nicht mehr reagierenden Slave zu ermitteln, richtig. Aber wenn Du synchrone Replikation verlangst, wird nicht einfach auf asynchrone umgeschaltet. Wir sind ja hier nicht bei MySQL oder so …
Mit 2 Slaves funktioniert die sychrone Replikation gut:
Solange ein slave gestartet werden alle updates am master schnell ausgeführt (kein Warten)
Wenn ein slave gestoppt wrid werden die WAL-files (pg_xlog) für den slot aufgehoben bis der slave wieder gestartet wird und synchron ist
Nur wenn beide slaves gestoppt sind wartet ein update am master “für immer”
Workaround: synchronous_standby_names=‘’ und reload configuration, mit terminate der hängenden transactions: damit wird async mode verwendet
Man kann offensichtlich zwischen synchronous und asyncrounous mode umschalten ohne den master server zu stoppen, reload mit unterschiedlichem synchronous_standby_names (leer oder gefüllt) genügt.
Der master erkennt einen Ausfall des slaves (kill oder stop) sofort (network error noch nicht getestet)
*** ABER: Unklar ist noch für mich,was das wal_sender_timeout wirklich bedeutet (nur bei “network outage”?), wann as wirkt, kann das jemand beantworten?
wal_sender_timeout (integer)
Terminate replication connections that are inactive longer than the specified number of milliseconds.
This is useful for the sending server to detect a standby crash or network outage.
A value of zero disables the timeout mechanism. This parameter can only be set in the postgresql.conf file or on the server command line.
The default value is 60 seconds.
Die verwendeten postgresql.conf settings:
wal_level = replica # Sonorys: for replication
synchronous_commit = on
archive_mode = on
archive_command = ‘cp -i %p /export/test_wal/indb_test1/%f </dev/null’
max_wal_senders = 5
wal_keep_segments = 10
wal_sender_timeout = 5s
max_replication_slots = 5
synchronous_standby_names = ‘1 (slave1, slave2)’
hot_standby_feedback = on
Du solltest synchronous_standby_names korrekt setzen, nicht auf ‘*’. Ab 9.6 kannst Du auch sagen, daß Du N synchrone haben willst aus einem Set von M Standbys (mit M > N) : synchronous_standby_names = 3(slave1, slave2, slave3, slave4, slave5) , in diesem Falle könnten z.B. bis zu 2 ausfallen.
Du kannst auch “SET LOCAL synchronous_commit TO OFF” in Transaktionen setzen, die Du NICHT synchron repliziert haben willst.
Das wal_sender_timeout dient der Erkennung, ob ein Standby noch da ist. Es steuert nicht das Verhalten der Replikation.
Nochmal: synchrone Replikation ist dann und nur dann sinnvoll, wenn Du mind. 2 Slaves hast. Synchrone Replikation erzwingt, daß die auf dem Master schreibende Applikation erst dann das COMMIT bekommt, wenn gemäß den Regeln bei synchronous_standby_names ein COMMIT erfolgen DARF.
Warum nicht? Zulässig ist es.
Damit wird doch einfach automatisch jeder Slave der sich anmeldet, zum synchronen Slave, oder?
Hmm. Warum?
Wenn ich sicherstellen will, dass der Slave immer zu 100% eine exakte Kopie des Masters ist und ich auf keinen Fall Daten verlieren will, dann macht synchrone Replikation doch auch mit einem Slave Sinn. Vor allem wenn man mit einem Load-Balancer arbeitet, der lesende Abfragen an den Slave weiterleitet.
Vor allem mit 9.6 kann das ja via “remote_apply” endlich 100% “korrekt” machen, so dass nach dem Schreiben auf dem Master die Daten wirklich sofort auf dem Slave zu sehen sind.
Aber ich hätte jetzt auch erwartet, dass der Master alleine weitermacht, wenn der eine Slave nicht mehr erreichbar ist (ob das Sinn macht, wenn man eigentlich keine Daten verlieren will ist eine andere Frage)
wenn man sync.repl. mit nur einem Slave macht muß man sich dessen bewußt sein.
Was das * betrifft: klar, damit ist jeder Standby angesprochen. Wenn man weiß, was man tut, …
Angenommen, Du hast 2 Standbys im selben RZ und noch einem auf dem Mars, mit einem hinreichend langem Delay also. Dann willst Du eher nicht, daß dieser mit sync. sein soll.
Was das ‘mind. 2’ betrifft: i.d.R. ist das Ziel einer Replikation eine verbesserte Ausfallsicherheit / Verfügbarkeit des Gesamtsystems. Synchrone Replikation mit nur 1 Slave erhöht aber eher die Wahrscheinlichkeit eines Ausfalles des Systems an sich, denn wenn der Slave ausfällt ist der auch der Master mehr oder weniger unbrauchbar.
Mit nur einem Slave würde der master auch “hängen” bleiben wenn der einzige slave ausfällt.
Wenn man das (automatisch mit periodischem script) jedoch überwacht (e.g. pg_stat_replication ) kann man ein reload machen mit synchronous_commit = off;
damit schaltet der master auf asynchron (für neu ankommende transaktionen)
Die “hängen gebliebenene” transaktionen kann man terminieren…
Ist natürlich ein workaround (aber spart resourcen für eine 2.Slave e.g. disk, cpu, server)
Mindestens 1x pro Tag (nachts bei wenig Last) pg_base_backup
base backups + alle Wal-files der letzten 2 backups auf archive-server speichern + Auf Band spielen
Täglich normales dump (data+scheme) für support zwecke - restauriert automatisch auf labor-rechnern
Das management der backups machen wir mit bacula
Wir überlengen 2 konzepte:
Konzept 1) Replikation via postgres-synchron normal / asynchron (nur temporär, e.g. wartungsfenster)
Wir haben 2 life-server ein Master und and standby (haben jeweils eigene ssd-disks)
Überwachung und umschaltung der Server via RGManager oder pacemaker (noch nicht entschieden)
Konzept 2) Disk-content replication
Eine Alternative ist auch noch untersucht: keine verwendung von postgres-replikation, sondern
“synchrone DISK” replikation: DRBD
… is a software-based, shared-nothing, replicated storage solution mirroring the content of block devices (hard disks, partitions, logical volumes etc.) between hosts.
(ich persönlich habe meine Bedenken bei DISK-replikation, obwohl synchron disk-local und disk-remote geschrieben werden,
könnte es bei Ausfällen zu “halb-übertragenen” Dateien kommen - ob das die Daten für postgres dann kapput machen kann…?)
DRBD ist kein ‘Backup’. Schaut Euch mal BARMAN an, das lohnt sich. Macht Basebackup + WAL archiving sowie WAL-Streaming, ist also (aus Sicht des Masters) wie ein Standbay in SR. Damit hast Du ein kontinuierliches Backup. Du kannst passende Retension-Policies definieren, sehr simpel ein Restore machen und so weiter. Ist auch in repmgr (REPlication ManaGeR) integriert, um z.B. einen neuen Standby hochzuziehen ohne Last auf dem Master zu generieren. Ist beides von meinen Kollegen entwickelt und von uns supported.