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

Ein Leitfaden für PGpool - Hinweise und Beobachtungen:Teil Drei

Im vorherigen Teil habe ich es gewagt, mit einem nicht implementierten Feature zu spielen und zu fantasieren, wie es funktionieren würde. Nun, HA ist in erster Linie eine Frage des Designs und erst dann der Implementierung. Es entschuldigt weder eine schlechte Implementierung, noch lässt es naives Design schlau aussehen. Doch nachdem Sie alle möglichen Szenarien abgedeckt und für die meisten Fälle eine angemessene beste Regel gefunden haben, kann manchmal eine sehr primitive kleine Änderung die Festung ruinieren. Unten möchte ich sandboxen.

Was passiert, wenn pgpool ein Failover durchführen soll, aber nicht kann?

Wenn die Zustandsprüfung für den Master fehlschlägt, wird der failover_command ausgelöst, um alle zu degenerieren oder den nächsten Slave zum primären zu machen. Klingt solide. Was ist, wenn es selbst fehlschlägt, z. B. die SSH-Verbindung fehlschlägt (z. B. weil ein anderer - schlechter Administrator den Schlüssel aus ~/.ssh/authorized_keys entfernt). Was haben wir?

Sobald health_check_timeout (Standard 20) abgelaufen ist (auch betroffen von Retry Delay, Max Retirement und so weiter), wird der Knoten tot, also:

t=# select nid,port,st 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
-----+------+------
   0 | 5400 | down
   1 | 5401 | up
   2 | 5402 | up
(3 rows)

Es sind also keine Wiederholungen mehr möglich und das Failover ist fehlgeschlagen. Die erste Option ist offensichtlich das manuelle Failover. Aber wenn das Failover aufgrund eines dummen Fehlers fehlgeschlagen ist, ist der Master wieder auf Schienen, und das einzige Problem, das Sie haben, ist, dass pgpool denkt, der Master sei offline - Sie würden die Dinge wahrscheinlich lieber so lassen, wie sie vor dem Unfall waren - richtig? Natürlich reicht es nicht aus, den Master einfach wieder online zu stellen. Pgpool hat den Primary bereits „degeneriert“. Es hilft auch nicht, es einfach als neuen Knoten hinzuzufügen. Das Schlimmste ist, dass pgpool nach dem Ereignis nicht versucht zu überprüfen, ob der alte Master pg_is_in_recovery() ist oder nicht, und ihn daher niemals als Primary akzeptiert. Laut Bugtrack müssen Sie mit dem Befehl pgpool -D „die pgpool_status-Datei verwerfen und den vorherigen Status nicht wiederherstellen“.

Nachdem wir den Status verworfen haben, verbinden wir uns erneut, um zu vermeiden, dass der Server die Verbindung unerwartet schließt, und führen Folgendes aus:

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 | up | primary
   1 | 5401 | up | standby
   2 | 5402 | up | standby
(3 rows)

Alle Knoten sind wieder aktiv und laufen, pgpool erkennt den Master.

Zum Schluss möchte ich noch einige Hinweise und Beobachtungen zur Verwendung von pgpool geben:

  • Das Ändern der Backend-Einstellungen ist etwas knifflig:Hostname, Port und Verzeichnis müssen neu geladen werden, um neue Knoten hinzuzufügen, müssen jedoch neu gestartet werden, um vorhandene zu bearbeiten. Während Gewicht und Flagge durch einfaches Neuladen geändert werden können.

  • Verwechseln Sie die Werte der Spalte load_balance_node nicht mit der Konfiguration. Wenn Sie nur einen Knoten mit wahr sehen, ist das nicht nur OK - es ist so gemeint. Dies bedeutet nicht, dass Sie nur einen Knoten im Ausgleichspool haben – es zeigt nur, welcher Knoten für diese bestimmte Sitzung ausgewählt wurde. Unten ist das Abfrageergebnis mit allen drei Knoten, die am Ausgleich der SELECT-Anweisungen teilnehmen, wobei die Knoten-ID 2 ausgewählt wurde:

    t=# show pool_nodes;
     node_id | hostname  | port | status | lb_weight |  role   | select_cnt | load_balance_node | replication_delay
    ---------+-----------+------+--------+-----------+---------+------------+-------------------+-------------------
     0       | localhost | 5400 | up     | 0.125000  | primary | 61         | false             | 0
     1       | localhost | 5401 | up     | 0.312500  | standby | 8          | false             | 0
     2       | localhost | 5402 | up     | 0.562500  | standby | 11         | true              | 0
    (3 rows)
  • Sie können mit show pool_nodes überprüfen, welcher Knoten für den Lastausgleich ausgewählt wurde, aber Sie möchten ihn für Ihre Abfrage wissen, nicht für die „show“, daher ist eine solche Überprüfung nicht immer informativ genug. Nun, Sie können überwachen, welchen Knoten Sie für die aktuelle Abfrage verwenden, mit etwas wie:

    t=# select *,current_setting('port') from now();
                  now              | current_setting
    -------------------------------+-----------------
     2018-04-09 13:56:17.501779+01 | 5401
    (1 row)

Wichtig! Aber nicht:

t=# select now, setting from now() join pg_settings on name='port';
             now             | setting
-----------------------------+---------
 2018-04-09 13:57:17.5229+01 | 5400
(1 row)

Da es IMMER den Port des Masters zurückgibt. Dasselbe gilt für jedes pg_catalog SELECT.

  • Wie Sie in den vorherigen Teilen bemerkt haben, verwende ich einen komplizierteren Weg, als nur pool_nodes anzuzeigen, um Knoten mit Status aufzulisten. Ich mache das bewusst, um zu demonstrieren, wie man das Ergebnis handhabbar machen kann. Die Verwendung von where macht die Abfrage länger, aber das Ergebnis klar, und überspringt alles, was die Aufmerksamkeit für unsere spezielle Aufgabe ablenkt. Vergleichen Sie:

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 | up | primary
   1 | 5401 | up | standby
   2 | 5402 | up | standby

Mit der Ausgabe von initial show pool_nodes...

  • Sie können pgbouncer und pgpool nicht vergleichen. Aber wenn Sie dies tun, ist es am wichtigsten zu wissen, dass das Analysieren von Abfragen in pgpool von der pg-Version abhängt. Wenn Sie also postgreSQL aktualisieren, müssen Sie auch pgpool aktualisieren, während eine pgbouncer-Instanz Konfigurationen für 8, 9, 10 verschiedene Cluster in derselben INI-Datei haben kann.

  • Warum kann ich nicht einfach ein Failover-Skript anstelle von pgpool verwenden? Sie können. Aber pgpool bietet es ZUSAMMEN mit memcached und Connection Pooling und Balancing und Split Brain Control und ist durch jahrzehntelange Nutzung geprüft.

  • Es ist ein Fehlerverfolgungssystem vorhanden - es lohnt sich, es zu besuchen, wenn Sie mit pgpool arbeiten:https://www.pgpool.net/mantisbt/my_view_page.php

  • Zahlreiche Tippfehler in der Dokumentation, wie bakance (backend + balance?..), statemnet, allowd oder mismatch across version (pool_nodes waren früher int und sind jetzt enum, aber Link zu alten Werten in pcp_node-info ist noch da) verderben den Eindruck auf dieses wunderbare Produkt. Ein Formular zum Senden des Berichts über gefundene „Fehler“ in der Dokumentation (genau wie „Korrektur übermitteln“ in Postgres-Dokumenten) würde dies jedoch erheblich verbessern.

  • Wichtiger Tipp: bevor Sie sich auf einen Schritt verlassen - überprüfen Sie ihn. Z.B. Nach dem Hochstufen des Knotens können Sie ihn nicht erneut hochstufen (hier ist das Hochstufen keine Postgres-Operation, sondern die Registrierung des Knotens als Master für pgpool):

    [email protected]:~# sudo -u postgres pcp_promote_node -w -h 127.0.0.1 -U vao -n 1
    pcp_promote_node -- Command Successful
    [email protected]:~# sudo -u postgres pcp_promote_node -w -h 127.0.0.1 -U vao -n 1
    FATAL:  invalid pgpool mode for process recovery request
    DETAIL:  specified node is already primary node, can't promote node id 1

Klingt logisch und sieht toll aus. Wenn Sie dies jedoch gegen einen falschen Knoten ausführen (z. B. Knoten 0 ist ! pg_is_in_recovery):

[email protected]:~# for i in $(seq 1 3); do pcp_promote_node -w -h 127.0.0.1 -U vao -n 0; echo $?; done
pcp_promote_node -- Command Successful
0
pcp_promote_node -- Command Successful
0
pcp_promote_node -- Command Successful
0

Was schlecht ist, weil Sie den Knoten nicht erneut hochstufen können und einen Fehler erwarten, aber Sie erhalten den Exit-Status 0 …

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

Wichtiger Tipp:Spielen Sie nicht zu viel. Spielen Sie niemals auf Prod!

Als ich mit dem Befehl recovery_1st_stage_command pg_rewind spielte, dachte ich, aus Neugierde einen anderen Affen-Hack auszuprobieren - pgpool_recovery() ohne Argumente abzufragen (da ich sie sowieso in meinem Setup ignoriere) und dann einfach zu versuchen, den Knoten an pgpool anzuhängen:

[email protected]:~# psql -p 5433 -h localhost template1 -c "SELECT pgpool_recovery('or_1st.sh', '', '', '')"
 pgpool_recovery
-----------------
 t
(1 row)

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

Diese dumme Idee brachte mich zu:

[email protected]:~# ps -aef | grep pgpool
postgres 15227     1  0 11:22 ?        00:00:00 pgpool -D
postgres 15240 15227  0 11:22 ?        00:00:00 pgpool: health check process(0)
postgres 15241 15227  0 11:22 ?        00:00:00 pgpool: health check process(1)
postgres 15242 15227  0 11:22 ?        00:00:00 pgpool: health check process(2)
postgres 15648 15227  0 11:24 ?        00:00:00 [pgpool] <defunct>
postgres 16264 15227  0 11:26 ?        00:00:00 pgpool: PCP: wait for connection request
postgres 16266 15227  0 11:26 ?        00:00:00 [pgpool] <defunct>
postgres 16506 16264  0 11:26 ?        00:00:00 pgpool: PCP: processing recovery request
postgres 16560 15227  0 11:26 ?        00:00:00 [pgpool] <defunct>
postgres 16835 15227  0 11:26 ?        00:00:00 [pgpool] <defunct>
postgres 16836 15227  0 11:26 ?        00:00:00 [pgpool] <defunct>

Ich muss nicht entkommen:

[email protected]:~# kill -9 
[email protected]:~# rm /var/run/pgpoolql/.s.PGSQL.5433
[email protected]:~# rm /var/run/pgpoolql/.s.PGSQL.9898

Über 5433 ist der pgpool-Port und 9898 ist der pcp-Port. Offensichtlich werden die Dateien nach dem Absturz nicht gefegt, also müssen Sie es manuell tun.

  • Lesen Sie sorgfältig und spielen Sie viel, bevor Sie pgpool in Produktion nehmen. Es ist viel schwieriger, Hilfe mit pgpool zu finden als mit postgres selbst. Manche Fragen werden nie beantwortet. Vor allem, wenn an der falschen Stelle gefragt wird (ich habe auf der Grundlage der richtigen Stelle geantwortet, um die Antwort zu erhalten) ...
  • Vergessen Sie nicht die neueste Zeitleiste für die kaskadierende Replikation (nicht wirklich der pgpool-Hinweis, aber oft verstehen die Leute nicht, dass es nicht ausreicht, einen richtigen Endpunkt für den Empfänger anzugeben, um einen neuen Master aufzunehmen).
  • li>
  • Architektur mit Diagramm finden Sie hier.

Schlussfolgerung

In 10 Jahren sind neue vielversprechende Features (Watchdog und Virtual IP) und wichtige Fixes (zB serialize_accept) aufgetaucht, aber insgesamt hinterlässt es einen unterbewerteten Eindruck. Docs haben Tippfehler, die dort seit 10 Jahren leben. Ich glaube nicht, dass niemand die Dokumente liest. Ich glaube nicht, dass es niemand bemerkt hat. Sie können sie einfach nicht auf einfache Weise melden. Es gibt viele geladene und vorbereitete Waffen, die auf dem Dokumentationsgelände liegen, damit der unerfahrene Benutzer sie nehmen, auf den Fuß richten und den Abzug betätigen kann. Ich habe keine vernünftige Idee, wie ich es verbessern könnte – ich warne nur die Schützen. Die Fehlinterpretation eines Parameters kann Sie in die verzweifelte Lage des Reverse Engineering bringen, um Ihren Fehler zu finden. All die Jahre war und ist pgpool eine Art Produkt für fortgeschrittene Benutzer. Beim Lesen der Dokumentation konnte ich nicht anders, als mich an den alten russischen Witz über Sherlock Holmes zu erinnern:Sherlock und Watson fliegen mit dem Ballon. Plötzlich weht der starke Wind sie tausende Kilometer weit weg. Als sie landen können, sehen sie das Mädchen, das Schafe weidet. Holmes fragt das Mädchen:„Liebling, wo sind wir?“ und das Mädchen antwortet „Du bist auf dem Ballon!“. Sherlock bedankt sich und sagt beim Abheben:„Der Wind hat uns sehr weit getragen – wir sind in Russland“. "Aber woher weißt du das?" fragt Watson. „Es ist offensichtlich – nur in Russland weiden Programmierer Schafe“, antwortet Sherlock. „Aber woher weißt du, dass das Mädchen Programmiererin ist?“ - "Es ist offensichtlich - sie hat uns absolut präzise und völlig nutzlose Antworten gegeben".