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

Eine Anleitung zu Pgpool für PostgreSQL:Teil Zwei

Dies ist der zweite Teil des Blogs „A Guide to Pgpool for PostgreSQL“. Den ersten Teil über Load Balancing, Session Pooling, In Memory Cache und Installation finden Sie hier.

Viele Benutzer suchen pgpool speziell nach Hochverfügbarkeitsfunktionen, und es hat viel zu bieten. Es gibt ziemlich viele Anleitungen für pgpool HA im Web (z. B. eine längere und eine kürzere), daher würde es keinen Sinn machen, sie zu wiederholen. Wir möchten auch keinen weiteren blinden Satz von Konfigurationswerten bereitstellen. Stattdessen schlage ich vor, gegen die Regeln zu spielen und es falsch zu machen, damit wir einige interessante Verhaltensweisen sehen. Eine der am meisten erwarteten Funktionen (zumindest oben auf der Seite) ist die Fähigkeit, die Verwendbarkeit eines „toten“ Ex-Masters zu erkennen und mit pg_rewind wiederzuverwenden. Es könnte Stunden sparen, den neuen Standby mit Big Data wiederherzustellen (da wir rsync oder pg_basebackup überspringen, wodurch effektiv ALLE Dateien vom neuen Master kopiert werden). Genau genommen ist pg_rewind für geplantes Failover (während Upgrade oder Migration auf neue Hardware) gedacht. Aber wir haben gesehen, wann es bei nicht geplantem, aber dennoch ordnungsgemäßem Herunterfahren und automatisiertem Failover sehr hilfreich ist - zum Beispiel macht ClusterControl davon Gebrauch, wenn es ein automatisches Failover von Replikations-Slaves durchführt. Nehmen wir an, wir haben den Fall:Wir brauchen (jeden) Master, der so weit wie möglich zugänglich ist. Wenn wir aus irgendeinem Grund (Netzwerkfehler, maximale Anzahl von Verbindungen überschritten oder ein anderer „Fehler“, der den Start neuer Sitzungen verbietet) keinen Master mehr für RW-Operationen verwenden können, haben wir einen Failover-Cluster konfiguriert, mit Slaves, die Verbindungen akzeptieren können. Wir können dann einen der Slaves hochstufen und auf ihn umschalten.

Nehmen wir zunächst an, wir haben drei Knoten:

  • 10.1.10.124:5400 mit /pg/10/m (pgpool dreht sich auch hier)
  • 10.1.10.147:5401 mit /pg/10/m2
  • 10.1.10.124:5402 mit /pg/10/s2

Das sind effektiv die gleichen Knoten wie in Teil eins, aber der Failover-Knoten wird auf einen anderen Host und $PGDATA verschoben. Ich habe es getan, um sicherzustellen, dass ich keinen Tippfehler gemacht oder ein zusätzliches Zitat im Remote-SSH-Befehl vergessen habe. Auch die Debugging-Informationen sehen einfacher aus, da die IP-Adressen unterschiedlich sind. Schließlich war ich mir nicht sicher, ob ich in der Lage sein werde, diesen nicht unterstützten Anwendungsfall zum Laufen zu bringen, also muss ich es mit eigenen Augen sehen.

Failover

Zuerst setzen wir failover_command und führen pgpool reload aus und versuchen ein Failover. Hier und weiter gebe ich einige Informationen an /tmp/d auf dem pgpool-Server zurück, damit ich -f /tmp/d anhängen kann, um den Fluss zu sehen.

[email protected]:~$ grep failover_command /etc/pgpool2/pgpool.conf
failover_command = 'bash /pg/10/fo.sh %D %H %R'

[email protected]:~$ cat /pg/10/fo.sh
rem_cmd="pg_ctl -D $3 promote"
cmd="ssh -T [email protected]$2 $rem_cmd"
echo "$(date) $cmd" >>/tmp/d
$cmd &>>/tmp/d

NB:Haben Sie $PATH in .bashrc auf dem Remote-Host gesetzt?..

Lasst uns den Meister stoppen (ich weiß, so kommt es nicht zu einer Katastrophe, man erwartet, dass zumindest ein riesiger Affe oder rot leuchtender Roboter den Server mit einem riesigen Hammer zerschmettert oder zumindest die langweiligen Festplatten sterben, aber ich benutze dieses anmutige Variante, um die mögliche Verwendung von pg_rewind zu demonstrieren, so dass hier das Failover das Ergebnis eines menschlichen Fehlers oder eines Netzwerkausfalls eine halbe Sekunde über die health_check_period ist), also:

/usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m stop
2018-04-18 13:53:55.469 IST [27433]  LOG:  received fast shutdown request
waiting for server to shut down....2018-04-18 13:53:55.478 IST [27433]  LOG:  aborting any active transactions
2018-04-18 13:53:55.479 IST [28855] postgres t FATAL:  terminating connection due to administrator command
2018-04-18 13:53:55.483 IST [27433]  LOG:  worker process: logical replication launcher (PID 27440) exited with exit code 1
2018-04-18 13:53:55.484 IST [27435]  LOG:  shutting down
2018-04-18 13:53:55.521 IST [27433]  LOG:  database system is shut down
 done
server stopped

Überprüfen Sie nun die Ausgabe des Failover-Befehls:

[email protected]:~$ cat /tmp/d
Wed Apr 18 13:54:05 IST 2018 ssh -T [email protected]
pg_ctl -D /pg/10/f promote
waiting for server to promote.... done
server promoted

Und nach einer Weile überprüfen:

t=# select nid,port,st, role from dblink('host=localhost port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int);
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | down | standby
   1 | 5401 | up   | primary
   2 | 5402 | up   | standby
(3 rows)

Außerdem sehen wir in Ex-Failover-Cluster-Protokollen:

2018-04-13 14:26:20.823 IST [20713]  LOG:  received promote request
2018-04-13 14:26:20.823 IST [20713]  LOG:  redo done at 0/951EC20
2018-04-13 14:26:20.823 IST [20713]  LOG:  last completed transaction was at log time 2018-04-13 10:41:54.355274+01
2018-04-13 14:26:20.872 IST [20713]  LOG:  selected new timeline ID: 2
2018-04-13 14:26:20.966 IST [20713]  LOG:  archive recovery complete
2018-04-13 14:26:20.998 IST [20712]  LOG:  database system is ready to accept connections

Replikation prüfen:

[email protected]:~$ psql -p 5401 t -c "select now() into test"
SELECT 1
[email protected]:~$ psql -p 5402 t -c "select * from test"
              now
-------------------------------
 2018-04-13 14:33:19.569245+01
(1 row)

Der Slave /pg/10/s2:5402 hat dank recovery_target_timeline =Latest in recovery.conf auf eine neue Timeline gewechselt, also sind wir gut. Wir müssen recovery.conf nicht so anpassen, dass es auf den neuen Master zeigt, da es auf die pgpool-IP und den Port verweist und sie gleich bleiben, egal wer die primäre Master-Rolle ausübt.

Load-Balancing prüfen:

[email protected]:~$ (for i in $(seq 1 9); do psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1" -XAt; done) | sort| uniq -c
      6 5401
      3 5402

Hübsch. Apps hinter pgpool bemerken einen zweiten Ausfall und funktionieren weiter.

Ex-Master wiederverwenden

Jetzt können wir den Ex-Master in den Failover-Standby schalten und ihn zurückbringen (ohne einen neuen Knoten zu pgpool hinzuzufügen, da er dort bereits vorhanden ist). Wenn Sie wal_log_hints oder Datenprüfsummen nicht aktiviert haben (umfassende Unterschiede zwischen diesen Optionen finden Sie hier), müssen Sie den Cluster auf dem Ex-Master neu erstellen, um einer neuen Zeitachse zu folgen:

[email protected]:~$ rm -fr /pg/10/m
[email protected]:~$ pg_basebackup -h localhost -p 5401 -D /pg/10/m/

Aber beeilen Sie sich nicht, die obigen Aussagen auszuführen! Wenn Sie auf wal_log_hints geachtet haben (Neustart erforderlich), können Sie versuchen, pg_rewind zu verwenden, um viel schneller vom Ex-Master auf einen neuen Slave umzuschalten.

Also ATM haben wir den Ex-Master offline, neuer Master mit nächster Timeline gestartet. Wenn der Ex-Master aufgrund eines vorübergehenden Netzwerkfehlers offline war und er wiederkommt, müssen wir ihn zuerst herunterfahren. Im obigen Fall wissen wir, dass es heruntergefahren ist, also können wir einfach versuchen, zurückzuspulen:

[email protected]:~$ pg_rewind -D /pg/10/m2 --source-server="port=5401 host=10.1.10.147"
servers diverged at WAL location 0/40605C0 on timeline 2
rewinding from last common checkpoint at 0/4060550 on timeline 2
Done!

Und nochmal:

[email protected]:~$ pg_ctl -D /pg/10/m2 start
server started
...blah blah 
[email protected]:~$ 2018-04-16 12:08:50.303 IST [24699]  LOG:  started streaming WAL from primary at 0/B000000 on timeline 2

t=# select nid,port,st,role from dblink('host=localhost port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int);
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | down | standby
   1 | 5401 | up   | primary
   2 | 5402 | up   | standby
(3 rows)

Ops. Duh! Trotz der Tatsache, dass der Cluster an Port 5400 online ist und einer neuen Zeitachse folgt, müssen wir pgpool anweisen, ihn zu erkennen:

[email protected]:~$ pcp_attach_node -w -h 127.0.0.1 -U vao -n 0
 pcp_attach_node  -- Command Successful

Jetzt sind alle drei aktiv (und pgpool weiß es) und synchron:

[email protected]:~$ sql="select ts.i::timestamp(0), current_setting('data_directory'),case when pg_is_in_recovery() then 'recovering' else 'mastering' end stream from ts order by ts desc"
[email protected]:~$ psql -h 10.1.10.147 -p 5401 t -c "$sql";
          i          | current_setting |  stream
---------------------+-----------------+-----------
 2018-04-30 14:34:36 | /pg/10/m2       | mastering
(1 row)

[email protected]:~$ psql -h 10.1.10.124 -p 5402 t -c "$sql";
          i          | current_setting |   stream
---------------------+-----------------+------------
 2018-04-30 14:34:36 | /pg/10/s2       | recovering
(1 row)

[email protected]:~$ psql -h 10.1.10.124 -p 5400 t -c "$sql";
          i          | current_setting |   stream
---------------------+-----------------+------------
 2018-04-30 14:34:36 | /pg/10/m        | recovering
(1 row)

Jetzt werde ich versuchen, recovery_1st_stage_command für die Wiederverwendung von Ex-Master zu verwenden:

[email protected]:~# grep 1st /etc/pgpool2/pgpool.conf
recovery_1st_stage_command = 'or_1st.sh'

Aber recovery_1st_stage_command bietet nicht die erforderlichen Argumente für pg_rewind, was ich sehen kann, wenn ich recovery_1st_stage_command hinzufüge:

echo "online recovery started on $(hostname) $(date --iso-8601) $0 $1 $2 $3 $4"; exit 1;

Die Ausgabe:

online recovery started on u2 2018-04-30 /pg/10/m2/or_1st.sh /pg/10/m2 10.1.10.124 /pg/10/m 5401

Nun - die Verwendung von pg_rewind ist nur in der Todo-Liste - was habe ich erwartet? .. Also muss ich einen Affenhack machen, um die Master-IP und den Port zu bekommen (denken Sie daran, dass es sich nach dem Failover ständig ändert).

Laden Sie noch heute das Whitepaper PostgreSQL-Verwaltung und -Automatisierung mit ClusterControl herunterErfahren Sie, was Sie wissen müssen, um PostgreSQL bereitzustellen, zu überwachen, zu verwalten und zu skalierenLaden Sie das Whitepaper herunter

Ein Affenhack

Also habe ich so etwas in recovery_1st_stage_command:

[email protected]:~# cat /pg/10/or_1st.sh
pgpool_host=10.1.10.124
pgpool_port=5433
echo "online recovery started on $(hostname) $(date --iso-8601) $0 $1 $2 $3 $4" | ssh -T $pgpool_host "cat >> /tmp/d"
master_port=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select port from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role='primary'")
master_host=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select hostname from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role='primary'")
failover_host=$(psql -XAt -h $pgpool_host -p $pgpool_port t -c "select hostname from dblink('host=$pgpool_host port=$pgpool_port','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int) where role!='primary' order by port limit 1")
src='"port=$master_port host=$master_host"'
rem_cmd="'pg_rewind -D $3 --source-server=\"port=$master_port host=$master_host\"'"
cmd="ssh -T $failover_host $rem_cmd"
echo $cmd | ssh -T $pgpool_host "cat >> /tmp/d"
$cmd

tmp=/tmp/rec_file_tmp
cat > $tmp <<EOF
standby_mode          = 'on'
primary_conninfo      = 'host=$master_host port=$master_port user=postgres'
trigger_file = '/tmp/tg_file'
recovery_target_timeline  = latest
EOF

scp $tmp $failover_host:$3/recovery.conf

rem_cmd="pg_ctl -D $3 start"
cmd="ssh -T $failover_host $rem_cmd"
echo $cmd | ssh -T $pgpool_host "cat >> /tmp/d"
$cmd
echo "OR finished $(date --iso-8601)" | ssh -T $pgpool_host "cat >> /tmp/d"
exit 0;

Was für ein Durcheinander! Nun - wenn Sie sich entscheiden, nicht vorhandene Funktionen zu verwenden - bereiten Sie sich vor - es wird schlecht aussehen, schlechter funktionieren und Sie werden sich dauerhaft für das schämen, was Sie getan haben. Also Schritt für Schritt:

  • Ich brauche pgpool IP und Port, um eine Remote-Verbindung herzustellen, sowohl um "show pool_nodes" abzufragen als auch um Schritte zu protokollieren und Befehle auszuführen.
  • Ich leite einige dbg-Informationen über ssh an /tmp/d weiter, da der Befehl auf der Master-Seite ausgeführt wird, was sich nach dem Failover ändert
  • Ich kann das Ergebnis von "show pool_nodes" verwenden, um die laufenden Master-Verbindungsinformationen zu erhalten, indem ich einfach mit der WHERE-Klausel filtere
  • Ich brauche doppelte Anführungszeichen im Argument für pg_rewind, das über ssh laufen muss, also teile ich den Befehl einfach zur besseren Lesbarkeit auf, gebe ihn dann wieder und führe ihn aus
  • Vorbereitung der recovery.conf basierend auf der Ausgabe von „show pool_nodes“ (beim Schreiben frage ich mich – warum habe ich nicht stattdessen einfach pgpool IP und Port verwendet?...)
  • Neuen Failover-Slave starten (Ich weiß, dass ich den 2. Schritt verwenden sollte - nur übersprungen, um zu vermeiden, dass alle IPs und Ports erneut abgerufen werden)

Nun, was bleibt - versuchen, dieses Durcheinander in PCP zu verwenden:

[email protected]:~# pcp_recovery_node -h 127.0.0.1 -U vao -n 0 -w
pcp_recovery_node -- Command Successful
[email protected]:~# psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port | st |  role
-----+------+----+---------
   0 | 5400 | up | standby
   1 | 5401 | up | primary
   2 | 5402 | up | standby
(3 rows)

Überprüfung von /tmp/d auf dem pgpool-Server:

[email protected]:~# cat /tmp/d
Tue May  1 11:37:59 IST 2018 ssh -T [email protected] /usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m2 promote
waiting for server to promote.... done
server promoted
online recovery started on u2 2018-05-01 /pg/10/m2/or_1st.sh /pg/10/m2
ssh -T 10.1.10.124 'pg_rewind -D --source-server="port=5401 host=10.1.10.147"'
ssh -T 10.1.10.124 pg_ctl -D start
OR finished 2018-05-01

Jetzt wollen wir es natürlich noch einmal wiederholen, um zu sehen, ob es auf irgendeinem Host funktioniert:

[email protected]:~$ ssh -T 10.1.10.147 pg_ctl -D /pg/10/m2 stop             waiting for server to shut down.... done
server stopped
[email protected]:~$ psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port |  st  |  role
-----+------+------+---------
   0 | 5400 | up   | primary
   1 | 5401 | down | standby
   2 | 5402 | up   | standby
(3 rows)

[email protected]:~# pcp_recovery_node -h 127.0.0.1 -U vao -n 1 -w

[email protected]:~$ psql -h localhost -p 5433 t -c"select nid,port,st,role from dblink('host=10.1.10.124 port=5433','show pool_nodes') as t (nid int,hostname text,port int,st text,lb_weight float,role text,cnt int,cur_node text,del int)"
 nid | port | st |  role
-----+------+----+---------
   0 | 5400 | up | primary
   1 | 5401 | up | standby
   2 | 5402 | up | standby
(3 rows)

Log sieht ähnlich aus - nur IP und Ports haben sich geändert:

 Tue May  1 11:44:01 IST 2018 ssh -T [email protected] /usr/lib/postgresql/10/bin/pg_ctl -D /pg/10/m promote
waiting for server to promote.... done
server promoted
online recovery started on u 2018-05-01 /pg/10/m/or_1st.sh /pg/10/m 10.1.10.147 /pg/10/m2 5400
ssh -T 10.1.10.147 'pg_rewind -D /pg/10/m2 --source-server="port=5400 host=10.1.10.124"'
ssh -T 10.1.10.147 pg_ctl -D /pg/10/m2 start
online recovery started on u 2018-05-01 /pg/10/m/or_1st.sh /pg/10/m
ssh -T 10.1.10.147 'pg_rewind -D --source-server="port=5400 host=10.1.10.124"'
ssh -T 10.1.10.147 pg_ctl -D start
OR finished 2018-05-01

In dieser Sandbox wechselte der Master bei einem Failover nach 5401 und nachdem er eine Weile dort gelebt hatte, wechselte er zurück zu 5400. Die Verwendung von pg_rewind sollte es so schnell wie möglich machen. Früher war der beängstigende Teil des automatischen Failovers:Wenn Sie die Konfiguration wirklich durcheinander gebracht und keine höhere Gewalt vorhergesehen haben, konnten Sie in ein automatisches Failover zum nächsten Slave und zum nächsten und zum nächsten laufen, bis kein freier Slave mehr übrig ist. Und danach haben Sie am Ende nur mehrere Split-Brain-Master und kein Failover-Ersatz. Es ist in einem solchen Szenario ein schwacher Trost, noch mehr Slaves für ein Failover zu haben, aber ohne pg_rewind hätten Sie nicht einmal das. „Traditionelles“ rsync oder pg_basebackup kopieren ALLE $PGDATA, um einen Standby zu erstellen, und können den „nicht allzu viel anderen“ Ex-Master nicht wiederverwenden.

Abschließend zu diesem Experiment möchte ich noch einmal betonen, dass dies keine Lösung ist, die sich für Blindkopien eignet. Die Verwendung von pg_rewind wird für pg_pool nicht empfohlen. Es ist nicht an allen Geldautomaten verwendbar. Ich wollte etwas frischen Wind in die pgpool HA-Konfiguration bringen, damit Nubes wie ich etwas genauer beobachten können, wie es funktioniert. Für Coryphaeus, um über naivistische Herangehensweise zu lächeln und es vielleicht mit unseren - nubischen Augen zu sehen.