PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Un guide de Pgpool pour PostgreSQL :deuxième partie

Ceci est la deuxième partie du blog "A Guide to Pgpool for PostgreSQL". La première partie couvrant l'équilibrage de charge, la mise en commun des sessions, le cache mémoire et l'installation se trouve ici.

De nombreux utilisateurs se tournent vers pgpool spécifiquement pour les fonctionnalités de haute disponibilité, et il a beaucoup à offrir. Il y a peu d'instructions pour pgpool HA sur le Web (par exemple, une plus longue et une plus courte), il n'est donc pas logique de les répéter. Nous ne voulons pas non plus fournir un autre ensemble aveugle de valeurs de configuration. Au lieu de cela, je suggère de jouer contre les règles et d'essayer de le faire dans le mauvais sens, nous verrons donc un comportement intéressant. L'une des fonctionnalités les plus attendues (du moins en haut de la page) est la possibilité de reconnaître l'utilisabilité d'un ancien maître "mort" et de le réutiliser avec pg_rewind. Cela pourrait faire gagner des heures à ramener le nouveau standby avec de grandes données (car nous sautons rsync ou pg_basebackup, qui copie effectivement TOUS les fichiers du nouveau maître). À proprement parler, pg_rewind est destiné au basculement planifié (lors d'une mise à niveau ou d'une migration vers un nouveau matériel). Mais nous avons vu quand cela aide grandement avec un arrêt non planifié mais pourtant gracieux et un basculement automatisé - par exemple, ClusterControl l'utilise lors de l'exécution du basculement automatique des esclaves de réplication. Supposons que nous ayons le cas :nous avons besoin que (n'importe quel) maître soit accessible autant que possible. Si pour une raison quelconque (défaillance du réseau, dépassement du nombre maximal de connexions ou tout autre "échec" qui interdit le démarrage de nouvelles sessions), nous ne pouvons plus utiliser de maître pour les opérations RW, nous avons configuré un cluster de basculement, avec des esclaves pouvant accepter les connexions. Nous pouvons alors promouvoir l'un des esclaves et basculer vers lui.

Supposons d'abord que nous ayons trois nœuds :

  • 10.1.10.124:5400 avec /pg/10/m (pgpool tourne ici aussi)
  • 10.1.10.147:5401 avec /pg/10/m2
  • 10.1.10.124:5402 avec /pg/10/s2

Ce sont effectivement les mêmes nœuds que dans la première partie, mais le nœud de basculement est déplacé vers un hôte différent et $PGDATA. Je l'ai fait pour m'assurer que je n'ai pas fait de faute de frappe ou oublié une citation supplémentaire dans la commande ssh distante. De plus, les informations de débogage seront plus simples car les adresses IP sont différentes. Enfin, je n'étais pas sûr de pouvoir faire fonctionner ce cas d'utilisation non pris en charge, je dois donc le voir de mes propres yeux.

Basculement

Nous définissons d'abord failover_command et exécutons pgpool reload et essayons de basculer. Ici et plus loin, je ferai écho à certaines informations sur /tmp/d sur le serveur pgpool, afin que je puisse suivre -f /tmp/d pour voir le flux.

[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 :avez-vous $PATH défini dans .bashrc sur l'hôte distant ? ..

Arrêtons le maître (je sais que ce n'est pas comme ça qu'un désastre se produit, vous vous attendez à ce qu'au moins un énorme singe ou un robot rouge brillant écrase le serveur avec un énorme marteau, ou au moins les disques durs ennuyeux meurent, mais j'utilise ce gracieux variante pour faire la démonstration de l'utilisation possible de pg_rewind, donc ici le basculement sera le résultat d'une erreur humaine ou d'une panne de réseau une demi-seconde au cours de la health_check_period), donc :

/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

Vérifiez maintenant la sortie de la commande de basculement :

[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

Et vérifiant après un moment :

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)

Nous voyons également dans les anciens journaux du cluster de basculement :

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

Vérification de la réplication :

[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)

L'esclave /pg/10/s2:5402 est passé à une nouvelle chronologie grâce à recovery_target_timeline =latest in recovery.conf, donc tout va bien. Nous n'avons pas besoin d'ajuster recovery.conf pour qu'il pointe vers le nouveau maître, car il pointe vers l'adresse IP et le port de pgpool et ils restent les mêmes, peu importe qui joue le rôle de maître principal.

Vérification de l'équilibrage de charge :

[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

Joli. Les applications derrière pgpool remarqueront une deuxième panne et continueront de fonctionner.

Réutiliser l'ancien maître

Nous pouvons maintenant mettre l'ancien maître en attente de basculement et le ramener (sans ajouter de nouveau nœud à pgpool, car il existe déjà là-bas). Si vous n'avez pas activé wal_log_hints ou les sommes de contrôle des données (la différence complète entre ces options est ici), vous devez recréer le cluster sur l'ex-maître pour suivre une nouvelle chronologie :

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

Mais ne vous précipitez pas pour exécuter les instructions ci-dessus ! Si vous avez pris soin de wal_log_hints (nécessite un redémarrage), vous pouvez essayer d'utiliser pg_rewind pour basculer beaucoup plus rapidement de l'ex-maître vers un nouvel esclave.

Donc ATM, nous avons l'ancien maître hors ligne, le nouveau maître avec la prochaine chronologie commencée. Si l'ancien maître était hors ligne en raison d'une panne temporaire du réseau et qu'il revient, nous devons d'abord l'arrêter. Dans le cas ci-dessus, nous savons qu'il est en panne, nous pouvons donc simplement essayer de rembobiner :

[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!

Et encore :

[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)

Opérations. Duh ! Malgré le fait que le cluster au port 5400 est en ligne et suit une nouvelle chronologie, nous devons dire à pgpool de le reconnaître :

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

Maintenant, tous les trois sont opérationnels (et pgpool le sait) et synchronisés :

[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)

Maintenant, je vais essayer d'utiliser recovery_1st_stage_command pour réutiliser l'ancien maître :

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

Mais recovery_1st_stage_command n'offre pas les arguments nécessaires pour pg_rewind, que je peux voir si j'ajoute à recovery_1st_stage_command :

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

La sortie :

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

Eh bien - l'utilisation de pg_rewind est juste dans la liste des tâches - à quoi m'attendais-je ? .. Je dois donc faire un hack de singe pour obtenir l'adresse IP et le port maître (rappelez-vous qu'il continuera à changer après le basculement).

Téléchargez le livre blanc aujourd'hui PostgreSQL Management &Automation with ClusterControlDécouvrez ce que vous devez savoir pour déployer, surveiller, gérer et faire évoluer PostgreSQLTélécharger le livre blanc

Un hack de singe

J'ai donc quelque chose comme ça dans 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;

Maintenant quel gâchis ! Eh bien - si vous décidez d'utiliser une fonctionnalité qui n'existe pas - préparez-vous - cela aura l'air mauvais, fonctionnera moins bien et vous aurez honte en permanence de ce que vous avez fait. Alors étape par étape :

  • J'ai besoin de l'adresse IP et du port de pgpool pour m'y connecter à distance, à la fois pour interroger "show pool_nodes" et pour enregistrer les étapes et exécuter des commandes.
  • Je transfère des informations dbg vers /tmp/d via ssh, car la commande sera exécutée côté maître, ce qui changera après le basculement
  • Je peux utiliser le résultat de "show pool_nodes" pour obtenir les informations de connexion maître en cours d'exécution en filtrant simplement avec la clause WHERE
  • J'aurai besoin de guillemets doubles dans l'argument pour pg_rewind, qui devra s'exécuter sur ssh, donc je divise simplement la commande pour la lisibilité, puis je lui fais un écho et je l'exécute
  • Préparer recovery.conf en fonction de la sortie de "show pool_nodes" (en l'écrivant, je me demande - pourquoi n'ai-je pas simplement utilisé l'adresse IP et le port de pgpool à la place ?
  • Démarrage d'un nouvel esclave de basculement (je sais que je suis censé utiliser la 2e étape - je l'ai simplement ignorée pour éviter de répéter toutes les adresses IP et tous les ports)

Maintenant, que reste-t-il - essayer d'utiliser ce gâchis dans pcp :

[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)

Vérification du /tmp/d sur le serveur pgpool :

[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

Maintenant, évidemment, nous voulons le relancer pour voir s'il fonctionne sur n'importe quel hôte :

[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)

Le journal se ressemble :seuls l'adresse IP et les ports ont changé :

 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

Dans ce bac à sable, le maître est passé à 5401 lors du basculement et après y avoir vécu pendant un certain temps, il est revenu à 5400. L'utilisation de pg_rewind devrait le rendre aussi rapide que possible. Auparavant, la partie effrayante du basculement automatique était - si vous gâchiez vraiment la configuration et ne prévoyiez pas de cas de force majeure, vous pouviez rencontrer un basculement automatique vers l'esclave suivant et suivant et suivant jusqu'à ce qu'il ne reste plus d'esclave libre. Et après cela, vous vous retrouvez avec plusieurs maîtres à cerveau divisé et aucune réserve de basculement. C'est une piètre consolation dans un tel scénario d'avoir encore plus d'esclaves au basculement, mais sans pg_rewind vous n'auriez même pas cela. rsync "traditionnel" ou pg_basebackup copient TOUS les $PGDATA pour créer un standby, et ne peuvent pas réutiliser l'ancien maître "pas trop différent".

En conclusion de cette expérience, je voudrais souligner une fois de plus - ce n'est pas une solution adaptée au collage de copie aveugle. L'utilisation de pg_rewind n'est pas encouragée pour pg_pool. Il n'est pas utilisable du tout ATM. Je voulais ajouter un peu d'air frais à la configuration pgpool HA, pour que les nubes comme moi observent d'un peu plus près comment cela fonctionne. Pour que coryphaeus sourie à l'approche naïve et peut-être le voit-il avec nos yeux - nubes.