sql >> Databasteknik >  >> RDS >> PostgreSQL

En guide till Pgpool för PostgreSQL:Del två

Detta är den andra delen av bloggen "A Guide to Pgpool for PostgreSQL". Den första delen som täcker lastbalansering, sessionspooling, i minnescache och installation finns här.

Många användare ser till pgpool specifikt för funktioner med hög tillgänglighet, och det har mycket att erbjuda. Det finns få ganska många instruktioner för pgpool HA på webben (t.ex. en längre och en kortare), så det skulle inte vara meningsfullt att upprepa dem. Vi vill inte heller tillhandahålla ännu en blind uppsättning konfigurationsvärden. Istället föreslår jag att du spelar mot reglerna och försöker göra det på fel sätt, så vi får se intressant beteende. En av de mest förväntade funktionerna (åtminstone är den högst upp på sidan) är förmågan att känna igen användbarheten av en "död" ex master och återanvända den med pg_rewind. Det kan spara timmar på att ta tillbaka det nya standbyläget med big data (eftersom vi hoppar över rsync eller pg_basebackup, som effektivt kopierar ALLA filer från den nya mastern). Strängt taget är pg_rewind avsedd för planerad failover (under uppgradering eller migrering till ny hårdvara). Men vi har sett när det är till stor hjälp med inte planerad men ändå graciös avstängning och automatiserad failover - till exempel använder ClusterControl det när man utför automatisk failover av replikeringsslavar. Låt oss anta att vi har fallet:vi behöver (vilken som helst) mästare för att vara tillgänglig så mycket som möjligt. Om vi ​​av någon anledning (nätverksfel, maxanslutningar överskrids eller något annat "fel" som förbjuder nya sessioner att starta) inte längre kan använda en master för RW-operationer, har vi ett failover-kluster konfigurerat, med slavar som kan acceptera anslutningar. Vi kan sedan befordra en av slavarna och misslyckas med den.

Låt oss först anta att vi har tre noder:

  • 10.1.10.124:5400 med /pg/10/m (pgpool snurrar även här)
  • 10.1.10.147:5401 med /pg/10/m2
  • 10.1.10.124:5402 med /pg/10/s2

Det är i praktiken samma noder som i del ett, men failovernoden flyttas till en annan värd och $PGDATA. Jag gjorde det för att se till att jag inte skrev fel eller glömde något extra citat i fjärrstyrt ssh-kommando. Även felsökningsinformationen kommer att se enklare ut eftersom ip-adresser är olika. Till slut var jag inte säker på att jag kommer att kunna få det här användningsfallet som inte stöds att fungera, så jag måste se det med mina egna ögon.

Failover

Först ställer vi in ​​failover_command och kör pgpool reload och försöker göra failover. Här och vidare kommer jag att eka lite information till /tmp/d på pgpool-servern, så att jag kan tail -f /tmp/d för att se flödet.

[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

OBS:Har du $PATH inställt i .bashrc på fjärrvärden?..

Låt oss stoppa mästaren (jag vet att det inte är så en katastrof händer, du förväntar dig åtminstone att någon enorm apa eller rödglänsande robot ska krossa servern med en stor hammare, eller åtminstone att de tråkiga hårddiskarna ska dö, men jag använder denna graciösa variant för att demonstrera möjlig användning av pg_rewind, så här kommer failover att vara resultatet av mänskliga fel eller nätverksfel en halv sekund under 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

Kontrollerar nu failover-kommandot:

[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

Och kollar efter ett tag:

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 också i ex-failover-klusterloggar:

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

Kontrollerar 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 bytte till en ny tidslinje tack vare recovery_target_timeline =senaste i recovery.conf, så vi är bra. Vi behöver inte justera recovery.conf för att peka på den nya mastern, eftersom den pekar på pgpool ip och port och de förblir desamma oavsett vem som utför den primära masterrollen.

Kontrollera lastbalansering:

[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

Trevlig. Appar bakom pgpool kommer att märka ett andra avbrott och fortsätter att fungera.

Återanvändning av ex-master

Nu kan vi ställa ex-mastern till failover-standby och ta tillbaka den (utan att lägga till en ny nod till pgpool, eftersom den redan finns där). Om du inte har aktiverat wal_log_hints eller datakontrollsummor (en omfattande skillnad mellan dessa alternativ finns här), måste du återskapa kluster på ex-master för att följa en ny tidslinje:

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

Men skynda dig inte att köra uttalandena ovan! Om du tog hand om wal_log_hints (kräver omstart), kan du prova att använda pg_rewind för mycket snabbare byte av ex-mastern till en ny slav.

Så ATM har vi ex-master offline, ny master med nästa tidslinje startas. Om ex-mastern var offline på grund av tillfälligt nätverksfel och den kommer tillbaka måste vi stänga av den först. I fallet ovan vet vi att det är nere, så vi kan bara försöka spola tillbaka:

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

Och 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! Trots att klustret vid port 5400 är online och följer en ny tidslinje, måste vi säga till pgpool att känna igen det:

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

Nu är alla tre uppe (och pgpool vet det) och synkroniserade:

[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 ska jag försöka använda recovery_1st_stage_command för att återanvända ex-master:

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

Men recovery_1st_stage_command erbjuder inte de nödvändiga argumenten för pg_rewind, som jag kan se om jag lägger till i recovery_1st_stage_command:

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

Utdata:

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

Tja - att använda pg_rewind är bara i att göra-listan - vad förväntade jag mig? .. Så jag måste göra lite monkey hack för att få master ip och port (kom ihåg att det kommer att fortsätta att ändras efter failover).

Ladda ner Whitepaper Today PostgreSQL Management &Automation med ClusterControlLäs om vad du behöver veta för att distribuera, övervaka, hantera och skala PostgreSQLDladda Whitepaper

Ett apahack

Så jag har något sånt här 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;

Vilken röra nu! Tja - om du bestämmer dig för att använda en funktion som inte finns - förbered dig - det kommer att se dåligt ut, fungera sämre och du kommer permanent att skämmas över det du gjorde. Så steg för steg:

  • Jag behöver pgpool IP och port för att fjärransluta till den, både för att fråga "show pool_nodes" och för att logga steg och för att köra kommandon.
  • Jag skickar lite dbg-information till /tmp/d över ssh, eftersom kommandot kommer att köras på huvudsidan, vilket kommer att ändras efter att ha misslyckats
  • Jag kan använda resultatet av "show pool_nodes" för att få informationen om den löpande huvudanslutningen genom att helt enkelt filtrera med WHERE-satsen
  • Jag kommer att behöva dubbla citattecken i argumentet för pg_rewind, som kommer att behöva köras över ssh, så jag delar bara kommandot för läsbarhet, sedan upprepar jag det och kör
  • Förbereder recovery.conf baserat på utdata från "show pool_nodes" (när jag skriver det frågar jag mig själv - varför använde jag inte bara pgpool IP och port istället?..
  • Startar ny failover-slav (jag vet att jag ska använda steg 2 - hoppade bara över för att undvika att få alla IP-adresser och portar igen)

Nu är det kvar - försöker använda den här röran 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)

Kontrollerar /tmp/d på pgpool-servern:

[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 vill vi uppenbarligen rulla över det igen för att se om det fungerar på någon värd:

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

Loggen ser likadan ut - endast IP och portar har ändrats:

 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 denna sandlåda flyttade mastern till 5401 vid failover och efter att ha bott där ett tag flyttade den tillbaka till 5400. Att använda pg_rewind borde göra det så snabbt som möjligt. Tidigare var den skrämmande delen av automatisk failover - om du verkligen förstörde konfigurationen och inte förutsåg någon force majeure, kunde du stöta på automatisk failover till nästa slav och nästa och nästa tills det inte finns någon ledig slav kvar. Och efter det slutar du bara med flera split brained masters och ingen reserv för failover. Det är en dålig tröst i ett sådant scenario att ha ännu fler slavar till failover, men utan pg_rewind skulle du inte ha ens det. "Traditionell" rsync eller pg_basebackup kopierar ALLA $PGDATA för att skapa ett standbyläge och kan inte återanvända den "inte alltför mycket annorlunda" ex master.

Som avslutning på detta experiment skulle jag vilja betona ännu en gång - detta är inte en lösning som lämpar sig för blindkopiering. Användningen av pg_rewind uppmuntras inte för pg_pool. Den är inte användbar alls ATM. Jag ville lägga till lite frisk luft till pgpool HA-konfigurationen, för att nuber som jag skulle kunna observera lite närmare hur det fungerar. För coryphaeus att le åt naivistiskt tillvägagångssätt och kanske se det med våra kärnögon.


  1. Varför finns det luckor i mina IDENTITY-kolumnvärden?

  2. Beteende av NOT LIKE med NULL-värden

  3. Hur man ändrar malldatabassamlingens kodning

  4. SQL-fel:ORA-00933:SQL-kommandot avslutades inte korrekt