Pgpool är mindre aktuell idag än för 10 år sedan, när det var standarddelen av en PostgreSQL-produktionsuppsättning. Ofta när någon pratade om PostgreSQL-kluster syftade de på postgreSQL bakom pgpool och inte till själva PostgreSQL-instansen (vilket är rätt term). Pgpool känns igen bland de flesta inflytelserika Postgres-spelare:postgresql-community, commandprompt, 2ndquadrant, EDB, citusdata, postgrespro (ordnad efter ålder, inte inflytande). Jag inser att nivån av igenkänning i mina länkar är väldigt olika - jag vill bara betona den övergripande effekten av pgpool i postgres-världen. Några av de mest kända nuvarande postgres "leverantörerna" hittades efter att pgpool redan var känd. Så vad gör den så berömd?
Bara listan över de mest efterfrågade funktionerna gör att det ser bra ut:
- native replikering
- anslutning pooling
- belastningsbalansering för lässkalbarhet
- hög tillgänglighet (vakthund med virtuell IP, onlineåterställning och failover)
Nåväl, låt oss göra en sandlåda och leka. Min provinställning är masterslavläge. Jag skulle anta att det är det mest populära idag, eftersom du vanligtvis använder strömmande replikering tillsammans med lastbalansering. Replikeringsläge används knappt nuförtiden. De flesta DBA:er hoppar över det till förmån för strömmande replikering och pglogical, och tidigare till slarvigt.
Replikeringsläget har många intressanta inställningar och säkert intressant funktionalitet. Men de flesta DBA:er har master/multislav setup när de kommer till pgpool. Så de letar efter automatisk failover och lastbalanserare, och pgpool erbjuder det direkt för befintliga master/multislav-miljöer. För att inte nämna att från och med Postgres 9.4 fungerar strömmande replikering utan större buggar och från 10 hashindex stöds replikering, så det finns knappt något som hindrar dig från att använda det. Också strömmande replikering är asynkron som standard (konfigurerbar till synkrona och till och med inte "linjära" synkroniseringskomplicerade inställningar, medan inbyggd pgpool-replikering är synkron (vilket innebär långsammare dataändringar) utan valmöjligheter. Ytterligare begränsningar gäller också. Pgpool-manualen själv föreslår att man föredrar när det är möjligt strömmande replikering över pgpool native one). Och så detta är mitt val här.
Ah, men först måste vi installera det - eller hur?
Installation (av högre version på ubuntu).
Kontrollera först ubuntu-versionen med lsb_release -a. För mig är repo:
[email protected]:~# sudo add-apt-repository 'deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
> sudo apt-key add -
OK
[email protected]:~# sudo apt-get update
Till sist själva installationen:
sudo apt-get install pgpool2=3.7.2-1.pgdg16.04+1
Konfig:
Jag använder standardkonfiguration från rekommenderat läge:
zcat /usr/share/doc/pgpool2/examples/pgpool.conf.sample-stream.gz > /etc/pgpool2/pgpool.conf
Startar:
Om du missade konfigurationen ser du:
2018-03-22 13:52:53.284 GMT [13866] FATAL: role "nobody" does not exist
Ah sant - min dåliga, men lätt att fixa (kan göras blint med en liner om du vill ha samma användare för alla hälsokontroller och återhämtning):
[email protected]:~# sed -i s/'nobody'/'pgpool'/g /etc/pgpool2/pgpool.conf
Och innan vi går vidare, låt oss skapa databasen pgpool och användarens pgpool i alla kluster (i min sandlåda är de master, failover och slav, så jag behöver bara köra det på master):
t=# create database pgpool;
CREATE DATABASE
t=# create user pgpool;
CREATE ROLE
Äntligen - börjar:
[email protected]:~$ /usr/sbin/service pgpool2 start
[email protected]:~$ /usr/sbin/service pgpool2 status
pgpool2.service - pgpool-II
Loaded: loaded (/lib/systemd/system/pgpool2.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2018-04-09 10:25:16 IST; 4h 14min ago
Docs: man:pgpool(8)
Process: 19231 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
Main PID: 8770 (pgpool)
Tasks: 10
Memory: 5.5M
CPU: 18.250s
CGroup: /system.slice/pgpool2.service
├─ 7658 pgpool: wait for connection reques
├─ 7659 pgpool: wait for connection reques
├─ 7660 pgpool: wait for connection reques
├─ 8770 /usr/sbin/pgpool -n
├─ 8887 pgpool: PCP: wait for connection reques
├─ 8889 pgpool: health check process(0
├─ 8890 pgpool: health check process(1
├─ 8891 pgpool: health check process(2
├─19915 pgpool: postgres t ::1(58766) idl
└─23730 pgpool: worker proces
Bra - så vi kan gå vidare till den första funktionen - låt oss kontrollera lastbalansering. Den har vissa krav som ska användas, stöder tips (t.ex. för att balansera i samma session), har svart-vit-listade funktioner, har reguljära uttrycksbaserad omdirigeringspreferenslista. Det är sofistikerat. Tyvärr, att gå igenom all den funktionaliteten noggrant skulle inte omfattas av denna blogg, så vi kommer att kolla de enklaste demos:
Först kommer något väldigt enkelt att visa vilken nod som används för att välja (i min installation, master spins på 5400, slav på 5402 och failover på 5401, medan pgpool själv är på 5433, eftersom jag har ett annat kluster igång och inte ville störa med det):
[email protected]:~$ psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1"
current_setting
-----------------
5400
(1 row)
Sedan i loop:
[email protected]:~$ (for i in $(seq 1 99); do psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1" -XAt; done) | sort| uniq -c
9 5400
30 5401
60 5402
Bra. Det balanserar definitivt belastningen mellan noder, men verkar inte balansera lika - kanske är det så smart att det vet vikten av varje påstående? Låt oss kontrollera distributionen med förväntade resultat:
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 | 122 | false | 0
1 | localhost | 5401 | up | 0.312500 | standby | 169 | false | 0
2 | localhost | 5402 | up | 0.562500 | standby | 299 | true | 0
(3 rows)
Nej - pgpool analyserar inte vikten av påståenden - det var en DBA med hennes inställningar igen! Inställningarna (se attributet lb_weight) överensstämmer med faktiska mål för frågemål. Du kan enkelt ändra det (som vi gjorde här) genom att ändra motsvarande inställning, t.ex.:
[email protected]:~$ grep weight /etc/pgpool2/pgpool.conf
backend_weight0 =0.2
backend_weight1 = 0.5
backend_weight2 = 0.9
[email protected]:~# sed -i s/'backend_weight2 = 0.9'/'backend_weight2 = 0.2'/ /etc/pgpool2/pgpool.conf
[email protected]:~# grep backend_weight2 /etc/pgpool2/pgpool.conf
backend_weight2 = 0.2
[email protected]:~# pgpool reload
[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
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 Bra! Nästa fantastiska funktion som erbjuds är anslutningspoolning. Med 3.5 löses problemet med "dundrande flock" genom att serialisera accept()-anrop, vilket avsevärt påskyndar "klientanslutningstiden". Och ändå är denna funktion ganska enkel. Den erbjuder inte flera nivåer av pooling eller flera pooler konfigurerade för samma databas (pgpool låter dig välja var du vill köra urval med database_redirect_preference_list av lastbalansering dock), eller andra flexibla funktioner som erbjuds av pgBouncer.
Så kort demo:
t=# select pid,usename,backend_type, state, left(query,33) from pg_stat_activity where usename='vao' and pid <> pg_backend_pid();
pid | usename | backend_type | state | left
------+---------+----------------+-------+--------------
8911 | vao | client backend | idle | DISCARD ALL
8901 | vao | client backend | idle | DISCARD ALL
7828 | vao | client backend | idle | DISCARD ALL
8966 | vao | client backend | idle | DISCARD ALL
(4 rows)
Hm - did I set up this little number of children?
t=# pgpool show num_init_children;
num_init_children
-------------------
4
(1 row)
Ah, sant, jag ändrade dem lägre än standard 32, så utdata skulle inte ta flera sidor. Nåväl, låt oss försöka överskrida antalet sessioner (nedan öppnar jag postgres-sessioner async in loop, så de 6 sessionerna skulle begäras mer eller mindre samtidigt):
[email protected]:~$ for i in $(seq 1 6); do (psql -h localhost -p 5433 t -U vao -c "select pg_backend_pid(), pg_sleep(1), current_setting('port'), clock_timestamp()" &); done
[email protected]:~$ pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+-------------------------------
8904 | | 5402 | 2018-04-10 12:46:55.626206+01
(1 row)
pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+-------------------------------
9391 | | 5401 | 2018-04-10 12:46:55.630175+01
(1 row)
pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+------------------------------
8911 | | 5400 | 2018-04-10 12:46:55.64933+01
(1 row)
pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+-------------------------------
8904 | | 5402 | 2018-04-10 12:46:56.629555+01
(1 row)
pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+-------------------------------
9392 | | 5402 | 2018-04-10 12:46:56.633092+01
(1 row)
pg_backend_pid | pg_sleep | current_setting | clock_timestamp
----------------+----------+-----------------+------------------------------
8910 | | 5402 | 2018-04-10 12:46:56.65543+01
(1 row)
Det låter sessioner komma med tre - förväntat, eftersom en tas av ovanstående session (välj från pg_stat_activity) så 4-1=3. Så fort pg_sleep avslutat sin ena tupplur och sessionen stängs av postgres, släpps nästa in. Så efter de första tre slutar, kliver de nästa tre in. Vad händer med resten? De står i kö tills nästa anslutningsplats frigörs. Sedan sker processen som beskrivs bredvid serialize_accept och klienten ansluts.
Va? Bara sessionspoolning i sessionsläge? Är allt?.. Nej, här kliver cachningen in! Titta.:
postgres=# /*NO LOAD BALANCE*/ select 1;
?column?
----------
1
(1 row)
Kontrollerar pg_stat_activity:
postgres=# select pid, datname, state, left(query,33),state_change::time(0), now()::time(0) from pg_stat_activity where usename='vao' and query not like '%DISCARD%';
pid | datname | state | left | state_change | now
-------+----------+-------+-----------------------------------+--------------+----------
15506 | postgres | idle | /*NO LOAD BALANCE*/ select 1, now | 13:35:44 | 13:37:19
(1 row)
Kör sedan den första satsen igen och observera att state_change inte ändras, vilket innebär att du inte ens kommer till databasen för att få ett känt resultat! Naturligtvis om du lägger in någon föränderlig funktion, kommer resultaten inte att cachas. Experimentera med:
postgres=# /*NO LOAD BALANCE*/ select 1, now();
?column? | now
----------+------------------------------
1 | 2018-04-10 13:35:44.41823+01
(1 row)
Du kommer att upptäcka att state_change ändras liksom resultatet.
Sista punkten här - varför /*NO LOAD BALANCE*/ ?.. för att vara säker kontrollerar vi pg_stat_activity på master och kör en fråga på master också. Samma som du kan använda /*NO QUERY CACHE*/-tips för att undvika att få ett cachat resultat.
Redan mycket för en kort recension? Men vi rörde inte ens HA-delen! Och många användare ser till pgpool specifikt för denna funktion. Tja, detta är inte slutet på historien, det här är slutet på del ett. Del två kommer, där vi kort kommer att täcka HA och några andra tips om hur man använder pgpool...