Pgpool is tegenwoordig minder actueel dan 10 jaar geleden, toen het het standaardonderdeel was van een PostgreSQL-productieconfiguratie. Vaak als iemand het had over PostgreSQL-cluster, verwezen ze naar postgreSQL achter pgpool en niet naar de PostgreSQL-instantie zelf (wat de juiste term is). Pgpool wordt erkend door de meest invloedrijke Postgres-spelers:postgresql-community, commandprompt, 2ndquadrant, EDB, citusdata, postgrespro (geordend op leeftijd, niet op invloed). Ik realiseer me dat het niveau van herkenning in mijn links heel anders is - ik wil alleen de algemene impact van pgpool in de postgres-wereld benadrukken. Enkele van de meest bekende huidige postgres "verkopers" werden gevonden nadat de pgpool al beroemd was. Dus wat maakt het zo beroemd?
Alleen al de lijst met de meest gevraagde functies zorgt ervoor dat het er geweldig uitziet:
- native replicatie
- pooling van verbindingen
- load balancing voor leesschaalbaarheid
- hoge beschikbaarheid (waakhond met virtueel IP-adres, online herstel &failover)
Laten we een zandbak maken en spelen. Mijn voorbeeldopstelling is de master-slave-modus. Ik neem aan dat dit tegenwoordig het populairst is, omdat je doorgaans streamingreplicatie gebruikt in combinatie met taakverdeling. De replicatiemodus wordt tegenwoordig nauwelijks gebruikt. De meeste DBA's slaan het over ten gunste van streaming-replicatie en pglogical, en eerder naar slony.
De replicatiemodus heeft veel interessante instellingen en zeker interessante functionaliteit. Maar de meeste DBA's hebben een master/multi-slave-configuratie tegen de tijd dat ze bij pgpool komen. Ze zijn dus op zoek naar automatische failover en load balancer, en pgpool biedt deze kant-en-klaar aan voor bestaande master/multi-slave-omgevingen. Om nog maar te zwijgen over het feit dat vanaf Postgres 9.4 streaming-replicatie zonder grote bugs werkt en dat replicatie vanaf 10 hash-indexen wordt ondersteund, dus er is nauwelijks iets dat u ervan weerhoudt het te gebruiken. Ook streaming-replicatie is standaard asynchroon (configureerbaar tot synchrone en zelfs niet "lineaire" synchronisatie gecompliceerde setups, terwijl native pgpool-replicatie synchroon is (wat langzamere gegevenswijzigingen betekent) zonder keuzeoptie. Er zijn ook aanvullende beperkingen van toepassing. Pgpool-handleiding zelf suggereert om de voorkeur te geven indien mogelijk streaming replicatie via pgpool native one). En dus is dit mijn keuze hier.
Ah, maar eerst moeten we het installeren - toch?
Installatie (van hogere versie op ubuntu).
Controleer eerst de ubuntu-versie met lsb_release -a. Voor mij is 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
Als laatste installatie zelf:
sudo apt-get install pgpool2=3.7.2-1.pgdg16.04+1
Configuratie:
Ik gebruik de standaardconfiguratie van de aanbevolen modus:
zcat /usr/share/doc/pgpool2/examples/pgpool.conf.sample-stream.gz > /etc/pgpool2/pgpool.conf
Beginnend:
Als je de configuratie hebt gemist, zie je:
2018-03-22 13:52:53.284 GMT [13866] FATAL: role "nobody" does not exist
Ah waar - mijn fout, maar gemakkelijk te repareren (blind te doen met één voering als je dezelfde gebruiker wilt voor alle gezondheidscontroles en herstel):
[email protected]:~# sed -i s/'nobody'/'pgpool'/g /etc/pgpool2/pgpool.conf
En voordat we verder gaan, laten we database pgpool en gebruiker pgpool maken in alle clusters (in mijn sandbox zijn ze master, failover en slave, dus ik hoef het alleen op master uit te voeren):
t=# create database pgpool;
CREATE DATABASE
t=# create user pgpool;
CREATE ROLE
Eindelijk - beginnend:
[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
Geweldig - dus we kunnen doorgaan naar de eerste functie - laten we de taakverdeling eens bekijken. Het heeft een aantal vereisten om te gebruiken, ondersteunt hints (bijv. om in dezelfde sessie te balanceren), heeft zwart-en-witte-lijstfuncties, heeft op reguliere expressies gebaseerde omleidingsvoorkeurenlijst. Het is verfijnd. Helaas zou het grondig doornemen van al die functionaliteit buiten het bestek van deze blog vallen, dus zullen we de eenvoudigste demo's bekijken:
Ten eerste zal iets heel eenvoudigs laten zien welk knooppunt wordt gebruikt om te selecteren (in mijn setup draait master op 5400, slave op 5402 en failover op 5401, terwijl pgpool zelf op 5433 staat, omdat ik een ander cluster heb draaien en niet wilde interfereren mee):
[email protected]:~$ psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1"
current_setting
-----------------
5400
(1 row)
Dan in lus:
[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
Super goed. Het balanceert zeker de belasting tussen knooppunten, maar lijkt niet gelijk in evenwicht te zijn - misschien is het zo slim dat het het gewicht van elke verklaring kent? Laten we eens kijken naar de verdeling met verwachte resultaten:
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)
Nee - pgpool analyseert het gewicht van uitspraken niet - het was weer een DBA met haar instellingen! De instellingen (zie het kenmerk lb_weight) komen overeen met de werkelijke doeldoelen van de query. U kunt het eenvoudig wijzigen (zoals we hier hebben gedaan) door de bijbehorende instelling te wijzigen, bijvoorbeeld:
[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
Download de whitepaper vandaag PostgreSQL-beheer en -automatisering met ClusterControlLees wat u moet weten om PostgreSQL te implementeren, bewaken, beheren en schalenDownload de whitepaper Super goed! De volgende geweldige functie die wordt aangeboden, is pooling van verbindingen. Met 3.5 is het "thundering kudde-probleem" opgelost door accept()-oproepen te serialiseren, waardoor de "clientverbinding" -tijd aanzienlijk wordt versneld. En toch is deze functie vrij eenvoudig. Het biedt niet meerdere niveaus van pooling of meerdere pools die zijn geconfigureerd voor dezelfde database (pgpool laat je kiezen waar je selecties wilt uitvoeren met database_redirect_preference_list van taakverdeling), of andere flexibele functies die worden aangeboden door pgBouncer.
Dus korte 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, waar, ik heb ze lager gewijzigd dan standaard 32, dus de uitvoer zou niet meerdere pagina's in beslag nemen. Laten we dan proberen het aantal sessies te overschrijden (hieronder open ik postgres-sessies async in lus, zodat de 6 sessies min of meer tegelijkertijd worden aangevraagd):
[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)
Het laat sessies aan drie komen - verwacht, aangezien één wordt genomen door de bovenstaande sessie (selecteren uit pg_stat_activity) dus 4-1=3. Zodra pg_sleep zijn dutje van één seconde beëindigt en de sessie wordt afgesloten door postgres, wordt de volgende binnengelaten. Dus nadat de eerste drie zijn afgelopen, komen de volgende drie binnen. Wat gebeurt er met de rest? Ze worden in de wachtrij geplaatst totdat het volgende verbindingsslot vrijkomt. Dan vindt het proces beschreven naast serialize_accept plaats en wordt de client verbonden.
Hoezo? Alleen sessiepooling in sessiemodus? Is het alles?.. Nee, hier komt de caching binnen! Kijk.:
postgres=# /*NO LOAD BALANCE*/ select 1;
?column?
----------
1
(1 row)
De pg_stat_activity controleren:
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)
Voer vervolgens de eerste instructie opnieuw uit en merk op dat state_change niet verandert, wat betekent dat u niet eens naar de database gaat om een bekend resultaat te krijgen! Als u een veranderlijke functie plaatst, worden de resultaten natuurlijk niet in de cache opgeslagen. Experimenteer met:
postgres=# /*NO LOAD BALANCE*/ select 1, now();
?column? | now
----------+------------------------------
1 | 2018-04-10 13:35:44.41823+01
(1 row)
Je zult zien dat state_change verandert, net als het resultaat.
Laatste punt hier - waarom /*NO LOAD BALANCE*/ ?.. om er zeker van te zijn, controleren we pg_stat_activity op master en voeren we ook een query uit op master. Hetzelfde kun je gebruiken /*NO QUERY CACHE*/ hint om te voorkomen dat je een resultaat in de cache krijgt.
Al veel voor een korte recensie? Maar we hebben het HA-gedeelte niet eens aangeraakt! En veel gebruikers kijken specifiek naar pgpool voor deze functie. Dit is niet het einde van het verhaal, dit is het einde van deel één. Deel twee komt eraan, waar we kort zullen ingaan op HA en enkele andere tips over het gebruik van pgpool...