Dette er anden del af bloggen "A Guide to Pgpool for PostgreSQL". Den første del, der dækker belastningsbalancering, sessionspooling, i hukommelsescache og installation kan findes her.
Mange brugere ser mod pgpool specifikt for funktioner med høj tilgængelighed, og det har masser at tilbyde. Der er få ret mange instruktioner til pgpool HA på nettet (f.eks. længere en og kortere), så det ville ikke give nogen mening at gentage dem. Vi ønsker heller ikke at give endnu et blindt sæt af konfigurationsværdier. I stedet foreslår jeg at spille imod reglerne og prøve at gøre det på den forkerte måde, så vi vil se noget interessant opførsel. En af de mest forventede funktioner (i det mindste er den øverst på siden) er evnen til at genkende anvendeligheden af en "død" ex-mester og genbruge den med pg_rewind. Det kan spare timer på at bringe den nye standby tilbage med big data (da vi springer rsync eller pg_basebackup over, som effektivt kopierer ALLE filer over fra den nye master). Strengt taget er pg_rewind beregnet til planlagt failover (under opgradering eller migrering til ny hardware). Men vi har set, hvornår det i høj grad hjælper med ikke planlagt, men alligevel yndefuld nedlukning og automatiseret failover - for eksempel gør ClusterControl brug af det, når der udføres automatisk failover af replikeringsslaver. Lad os antage, at vi har sagen:Vi har brug for (enhver) mester for at være tilgængelig så meget som muligt. Hvis vi af en eller anden grund (netværksfejl, maksimale forbindelser overskredet eller enhver anden "fejl", der forbyder nye sessioner at starte) ikke længere kan bruge en master til RW-operationer, har vi en failover-klynge konfigureret med slaver, der kan acceptere forbindelser. Vi kan så forfremme en af slaverne og svigte over til den.
Lad os først antage, at vi har tre noder:
- 10.1.10.124:5400 med /pg/10/m (pgpool spins også her)
- 10.1.10.147:5401 med /pg/10/m2
- 10.1.10.124:5402 med /pg/10/s2
Det er faktisk de samme noder som i del et, men failover-knuden flyttes til en anden vært og $PGDATA. Jeg gjorde det for at sikre mig, at jeg ikke skrev fejl eller glemte et ekstra citat i den eksterne ssh-kommando. Også fejlretningsoplysningerne vil se enklere ud, fordi ip-adresser er forskellige. Endelig var jeg ikke sikker på, at jeg ville være i stand til at få denne ikke-understøttede use case til at fungere, så jeg er nødt til at se den med mine egne øjne.
Failover
Først indstiller vi failover_command og kører pgpool reload og prøver at failover. Her og længere vil jeg ekko noget info til /tmp/d på pgpool-serveren, så jeg kan følge -f /tmp/d for at se flowet.
[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:Har du $PATH sat i .bashrc på fjernvært?..
Lad os stoppe mesteren (jeg ved godt, at det ikke er sådan en katastrofe sker, du forventer i det mindste en kæmpe abe eller en rød skinnende robot til at smadre serveren med en kæmpe hammer, eller i det mindste de kedelige harddiske dør, men jeg bruger denne yndefulde variant til at demonstrere den mulige brug af pg_rewind, så her vil failover være resultatet af menneskelige fejl eller netværksfejl et halvt sekund i løbet af health_check_perioden), så:
/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
Kontrollerer nu failover-kommandoens output:
[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
Og tjekker efter et stykke tid:
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)
Vi ser også i tidligere failover-klyngelogfiler:
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
Kontrollerer replikering:
[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)
Slaven /pg/10/s2:5402 skiftede til en ny tidslinje takket være recovery_target_timeline =senest i recovery.conf, så vi er gode. Vi behøver ikke justere recovery.conf til at pege på den nye master, fordi den peger på pgpool ip og port, og de forbliver de samme, uanset hvem der udfører den primære masterrolle.
Kontrol af belastningsbalancering:
[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
Pæn. Apps bag pgpool vil bemærke endnu et afbrydelse og fortsætte med at arbejde.
Genbrug af ex-master
Nu kan vi slå den tidligere master til failover-standby og bringe den tilbage (uden at tilføje en ny node til pgpool, da den allerede eksisterer der). Hvis du ikke har aktiveret wal_log_hints eller datakontrolsummer (omfattende forskel mellem disse muligheder er her), skal du genskabe klynge på ex-master for at følge en ny tidslinje:
[email protected]:~$ rm -fr /pg/10/m
[email protected]:~$ pg_basebackup -h localhost -p 5401 -D /pg/10/m/
Men skynd dig ikke at køre ovenstående udtalelser! Hvis du var omhyggelig med wal_log_hints (kræver genstart), kan du prøve at bruge pg_rewind for meget hurtigere at skifte fra den tidligere master til en ny slave.
Så ATM har vi den tidligere mester offline, ny mester med næste tidslinje startet. Hvis den tidligere master var offline på grund af midlertidig netværksfejl, og den kommer tilbage, skal vi lukke den ned først. I ovenstående tilfælde ved vi, at den er nede, så vi kan bare prøve at spole tilbage:
[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!
Og igen:
[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! På trods af at klyngen ved port 5400 er online og følger en ny tidslinje, er vi nødt til at bede pgpool om at genkende den:
[email protected]:~$ pcp_attach_node -w -h 127.0.0.1 -U vao -n 0
pcp_attach_node -- Command Successful
Nu er alle tre oppe (og pgpool ved det) og synkroniseret:
[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)
Nu vil jeg prøve at bruge recovery_1st_stage_command til at genbruge ex-master:
[email protected]:~# grep 1st /etc/pgpool2/pgpool.conf
recovery_1st_stage_command = 'or_1st.sh'
Men recovery_1st_stage_command tilbyder ikke de nødvendige argumenter for pg_rewind, som jeg kan se, hvis jeg tilføjer til recovery_1st_stage_command:
echo "online recovery started on $(hostname) $(date --iso-8601) $0 $1 $2 $3 $4"; exit 1;
Udgangen:
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
Nå - at bruge pg_rewind er bare på todo-listen - hvad forventede jeg?.. Så jeg er nødt til at lave noget monkey hack for at få master ip og port (husk det vil blive ved med at ændre sig efter failover).
Download Whitepaper Today PostgreSQL Management &Automation med ClusterControlFå flere oplysninger om, hvad du skal vide for at implementere, overvåge, administrere og skalere PostgreSQLDownload WhitepaperEt abehack
Så jeg har sådan noget i 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;
Nu hvilket rod! Nå - hvis du beslutter dig for at bruge en ikke eksisterende funktion - forbered dig - det vil se dårligt ud, virke dårligere, og du vil permanent skamme dig over det, du gjorde. Så trin for trin:
- Jeg har brug for pgpool IP og port for at fjernforbindelse til den, både for at forespørge "show pool_nodes" og for at logge trin og for at køre kommandoer.
- Jeg overfører nogle dbg-oplysninger til /tmp/d over ssh, fordi kommandoen vil blive udført på mastersiden, som vil ændre sig efter fejl over
- Jeg kan bruge resultatet af "vis pool_nodes" til at få de kørende hovedforbindelsesoplysninger til ganske enkelt at filtrere med WHERE-sætning
- Jeg skal bruge dobbelte anførselstegn i argumentet for pg_rewind, som skal køre over ssh, så jeg opdeler bare kommandoen for at kunne læse den, og derefter gentage den og køre
- Forbereder recovery.conf baseret på output fra "show pool_nodes" (hvis jeg skriver det, spørger jeg mig selv - hvorfor brugte jeg ikke bare pgpool IP og port i stedet?..
- Starter ny failover-slave (jeg ved, jeg skal bruge 2. trin - bare sprunget over for at undgå at få alle IP'er og port igen)
Hvad er der nu tilbage - prøver at bruge dette rod i 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)
Kontrollerer /tmp/d på pgpool-serveren:
[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
Nu vil vi selvfølgelig rulle det om igen for at se, om det virker på en hvilken som helst vært:
[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 ligner hinanden - kun IP og porte er ændret:
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
I denne sandkasse flyttede masteren til 5401 ved failover, og efter at have boet der et stykke tid flyttede den tilbage til 5400. Brug af pg_rewind skulle gøre det så hurtigt som muligt. Tidligere var den skræmmende del af automatisk failover - hvis du virkelig rodede konfigurationen og ikke forudså en eller anden force majeure, kunne du løbe ind i automatisk failover til næste slave og næste og næste, indtil der ikke er nogen fri slave tilbage. Og herefter ender du bare med flere splittede mestre og ingen failover-reserve. Det er en dårlig trøst i et sådant scenarie at have endnu flere slaver til failover, men uden pg_rewind ville du ikke have selv det. "Traditionel" rsync eller pg_basebackup kopierer ALLE $PGDATA over for at skabe en standby og kan ikke genbruge den "ikke for meget anderledes" ex master.
Som afslutning på dette eksperiment vil jeg endnu en gang understrege - dette er ikke en løsning, der er egnet til blind copy pasting. Brugen af pg_rewind opfordres ikke til pg_pool. Det er slet ikke brugbart ATM. Jeg ønskede at tilføje noget frisk luft til pgpool HA-konfigurationen, for nubes som mig at observere lidt nærmere, hvordan det virker. For coryphaeus at smile ved naivistisk tilgang og måske se det med vores nubes øjne.