PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Una guida a Pgpool per PostgreSQL:parte seconda

Questa è la seconda parte del blog “A Guide to Pgpool for PostgreSQL”. La prima parte relativa al bilanciamento del carico, al pool di sessioni, alla cache di memoria e all'installazione può essere trovata qui.

Molti utenti guardano a pgpool specificamente per le funzionalità ad alta disponibilità e ha molto da offrire. Ci sono poche istruzioni per pgpool HA sul web (ad esempio una più lunga e una più corta), quindi non avrebbe alcun senso ripeterle. Né vogliamo fornire ancora un altro set cieco di valori di configurazione. Invece suggerisco di giocare contro le regole e provare a farlo nel modo sbagliato, così vedremo dei comportamenti interessanti. Una delle caratteristiche più attese (almeno è in cima alla pagina) è la capacità di riconoscere l'usabilità di un ex master "morto" e riutilizzarla con pg_rewind. Potrebbe risparmiare ore nel riportare il nuovo standby con i big data (poiché saltiamo rsync o pg_basebackup, che copia efficacemente TUTTI i file dal nuovo master). A rigor di termini, pg_rewind è pensato per il failover pianificato (durante l'aggiornamento o la migrazione a nuovo hardware). Ma abbiamo visto quando è di grande aiuto con l'arresto non pianificato ma ancora regolare e il failover automatizzato, ad esempio ClusterControl ne fa uso quando esegue il failover automatico degli slave di replica. Supponiamo di avere il caso:abbiamo bisogno di (qualsiasi) master per essere il più possibile accessibile. Se per qualche motivo (errore di rete, numero massimo di connessioni superato o qualsiasi altro "errore" che impedisce l'avvio di nuove sessioni) non possiamo più utilizzare un master per le operazioni RW, abbiamo configurato un cluster di failover, con slave che possono accettare connessioni. Possiamo quindi promuovere uno degli schiavi e fallire su di esso.

Per prima cosa supponiamo di avere tre nodi:

  • 10.1.10.124:5400 con /pg/10/m (pgpool gira anche qui)
  • 10.1.10.147:5401 con /pg/10/m2
  • 10.1.10.124:5402 con /pg/10/s2

Questi sono effettivamente gli stessi nodi della prima parte, ma il nodo di failover viene spostato su un host diverso e $PGDATA. L'ho fatto per assicurarmi di non scrivere errori di battitura o dimenticare qualche citazione in più nel comando ssh remoto. Anche le informazioni di debug sembreranno più semplici perché gli indirizzi IP sono diversi. Alla fine non ero sicuro di riuscire a far funzionare questo caso d'uso non supportato, quindi devo vederlo con i miei occhi.

Failover

Per prima cosa impostiamo failover_command ed eseguiamo pgpool reload e proviamo a eseguire il failover. Qui e oltre, farò eco ad alcune informazioni su /tmp/d sul server pgpool, così posso tail -f /tmp/d per vedere il flusso.

[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:hai $PATH impostato in .bashrc sull'host remoto?..

Fermiamo il master (so che non è così che accade il disastro, ti aspetti che almeno una scimmia enorme o un robot rosso brillante distrugga il server con un enorme martello, o almeno che i noiosi dischi rigidi muoiano, ma sto usando questo grazioso variante per dimostrare il possibile utilizzo di pg_rewind, quindi qui il failover sarà il risultato di un errore umano o di un errore di rete di mezzo secondo nel periodo di health_check), quindi:

/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

Ora controllando l'output del comando di failover:

[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

E dopo un po' controlli:

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)

Inoltre vediamo nei log del cluster ex failover:

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

Verifica della replica:

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

Lo slave /pg/10/s2:5402 è passato a una nuova timeline grazie a recovery_target_timeline =latest in recovery.conf, quindi siamo a posto. Non è necessario modificare recovery.conf in modo che punti al nuovo master, perché punta all'ip e alla porta di pgpool e rimangono gli stessi indipendentemente da chi sta svolgendo il ruolo di master principale.

Verifica del bilanciamento del carico:

[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

Bello. Le app dietro pgpool noteranno una seconda interruzione e continueranno a funzionare.

Riutilizzo dell'ex maestro

Ora possiamo trasformare l'ex master in standby di failover e riportarlo indietro (senza aggiungere un nuovo nodo a pgpool, poiché esiste già lì). Se non hai wal_log_hints abilitato o checksum dei dati (la differenza completa tra queste opzioni è qui), devi ricreare il cluster su ex-master per seguire una nuova sequenza temporale:

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

Ma non affrettarti a eseguire le affermazioni di cui sopra! Se ti sei preso cura di wal_log_hints (richiede il riavvio), puoi provare a usare pg_rewind per passare molto più velocemente dall'ex master a un nuovo slave.

Quindi ATM abbiamo l'ex master offline, nuovo master con la prossima sequenza temporale iniziata. Se l'ex master era offline a causa di un guasto temporaneo della rete e torna indietro, dobbiamo prima spegnerlo. Nel caso sopra sappiamo che è inattivo, quindi possiamo semplicemente provare a riavvolgere:

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

E ancora:

[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. Eh! Nonostante il cluster alla porta 5400 sia online e segua una nuova linea temporale, dobbiamo dire a pgpool di riconoscerlo:

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

Ora tutti e tre sono attivi (e pgpool lo sa) e sincronizzati:

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

Ora proverò a utilizzare recovery_1st_stage_command per riutilizzare l'ex master:

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

Ma recovery_1st_stage_command non offre gli argomenti necessari per pg_rewind, che posso vedere se aggiungo recovery_1st_stage_command:

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

L'uscita:

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

Bene, l'uso di pg_rewind è solo nell'elenco delle cose da fare:cosa mi aspettavo?.. Quindi ho bisogno di fare qualche hack per ottenere l'ip principale e la porta (ricorda che continuerà a cambiare dopo il failover).

Scarica il whitepaper oggi Gestione e automazione di PostgreSQL con ClusterControlScopri cosa devi sapere per distribuire, monitorare, gestire e ridimensionare PostgreSQLScarica il whitepaper

Un trucco da scimmia

Quindi ho qualcosa del genere 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;

Ora che casino! Bene - se decidi di utilizzare funzionalità non esistenti - preparati - sembrerà brutto, funzionerà peggio e ti vergognerai permanentemente di quello che hai fatto. Quindi passo dopo passo:

  • Ho bisogno dell'IP e della porta di pgpool per connettermi in remoto ad esso, sia per interrogare "show pool_nodes" che per registrare i passaggi ed eseguire comandi.
  • Sto inviando alcune informazioni dbg a /tmp/d su ssh, perché il comando verrà eseguito sul lato master, che cambierà dopo il failover
  • Posso usare il risultato di "show pool_nodes" per ottenere le informazioni sulla connessione master in esecuzione semplicemente filtrando con la clausola WHERE
  • Avrò bisogno di virgolette doppie nell'argomento per pg_rewind, che dovrà essere eseguito su ssh, quindi ho appena diviso il comando per la leggibilità, quindi ripeto ed eseguito
  • Preparazione di recovery.conf in base all'output di "show pool_nodes" (scrivendolo mi chiedo - perché non ho semplicemente usato pgpool IP e port?..
  • Avvio di un nuovo slave di failover (so che dovrei usare il 2° passaggio, appena saltato per evitare di recuperare tutti gli IP e le porte)

Ora cosa resta:provare a usare questo pasticcio in 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)

Controllo di /tmp/d sul server 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

Ora ovviamente vogliamo ripetere il rollover per vedere se funziona su qualsiasi host:

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

Il registro è simile:sono cambiati solo IP e porte:

 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 questa sandbox, il master è passato a 5401 in fase di failover e dopo aver vissuto lì per un po' è tornato a 5400. L'uso di pg_rewind dovrebbe renderlo il più veloce possibile. In precedenza, la parte spaventosa del failover automatico era:se hai davvero incasinato la configurazione e non prevedevi una causa di forza maggiore, potresti imbatterti in un failover automatico sullo slave successivo e successivo e successivo fino a quando non è rimasto nessuno slave libero. E dopo, ti ritroverai con diversi master con il cervello diviso e nessun ricambio di failover. È una scarsa consolazione in uno scenario del genere avere ancora più slave per il failover, ma senza pg_rewind non avresti nemmeno quello. rsync "tradizionale" o pg_basebackup copia TUTTO $PGDATA per creare uno standby e non può riutilizzare l'ex master "non troppo diverso".

In conclusione di questo esperimento vorrei sottolineare ancora una volta che questa non è una soluzione adatta per il copia incolla alla cieca. L'uso di pg_rewind non è incoraggiato per pg_pool. Non è utilizzabile in tutti gli ATM. Volevo aggiungere un po' d'aria fresca alla configurazione di pgpool HA, per i nubes come me per osservare un po' più da vicino come funziona. Affinché Coryphaeus sorrida all'approccio ingenuo e magari lo veda con i nostri - nubes occhi.