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

En guide til Pgpool til PostgreSQL:del 1

Pgpool er mindre aktuelt i dag, end det plejede at være for 10 år siden, da det var standarddelen af ​​en PostgreSQL-produktionsopsætning. Ofte, når nogen talte om PostgreSQL-klynge, henviste de til postgreSQL bag pgpool og ikke til selve PostgreSQL-forekomsten (som er det rigtige udtryk). Pgpool er genkendt blandt de mest indflydelsesrige Postgres-spillere:postgresql-fællesskab, kommandoprompt, 2. kvadrant, EDB, citusdata, postgrespro (ordnet efter alder, ikke indflydelse). Jeg er klar over, at niveauet af genkendelse i mine links er meget anderledes - jeg vil blot understrege den overordnede effekt af pgpool i postgres-verdenen. Nogle af de mest kendte nuværende postgres "leverandører" blev fundet, efter at pgpool allerede var berømt. Så hvad gør den så berømt?

Bare listen over de mest efterspurgte tilbudte funktioner får det til at se godt ud:

  • native replikering
  • forbindelsespooling
  • belastningsbalancering for læseskalerbarhed
  • høj tilgængelighed (vagthund med virtuel IP, onlinegendannelse og failover)

Nå, lad os lave en sandkasse og lege. Min prøveopsætning er master slave-tilstand. Jeg vil antage, at det er det mest populære i dag, fordi man typisk bruger streaming replikering sammen med load balancing. Replikeringstilstand bruges næsten ikke i disse dage. De fleste DBA'er springer det over til fordel for streaming-replikering og pglogical, og tidligere til slony.

Replikeringstilstanden har mange interessante indstillinger og sikkert interessant funktionalitet. Men de fleste DBA'er har master/multi slave setup, når de kommer til pgpool. Så de leder efter automatisk failover og load balancer, og pgpool tilbyder det ud af boksen til eksisterende master/multi slave-miljøer. For ikke at nævne, at fra Postgres 9.4 fungerer streaming-replikering uden større fejl, og fra 10 hash-indekser understøttes replikering, så der er næsten ikke noget, der forhindrer dig i at bruge det. Også streamingreplikering er asynkron som standard (kan konfigureres til synkron og endda ikke "lineær" synkronisering komplicerede opsætninger, mens native pgpool-replikering er synkron (hvilket betyder langsommere dataændringer) uden valgmulighed. Der gælder også yderligere begrænsninger. Pgpool-manualen foreslår selv at foretrække når det er muligt, streaming replikering over pgpool native one). Og så dette er mit valg her.

Ah, men først skal vi installere det - ikke?

Installation (af højere version på ubuntu).

Tjek først ubuntu-versionen med lsb_release -a. For mig er 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

Til sidst selve installationen:

sudo apt-get install pgpool2=3.7.2-1.pgdg16.04+1

Konfig:

Jeg bruger standardkonfiguration fra anbefalet tilstand:

zcat /usr/share/doc/pgpool2/examples/pgpool.conf.sample-stream.gz > /etc/pgpool2/pgpool.conf

Starter:

Hvis du gik glip af konfigurationen, ser du:

2018-03-22 13:52:53.284 GMT [13866] FATAL:  role "nobody" does not exist

Ah sandt - min dårlige, men let fixable (kan gøres blindt med en liner, hvis du vil have den samme bruger til alle sundhedstjek og genopretning):

[email protected]:~# sed -i s/'nobody'/'pgpool'/g /etc/pgpool2/pgpool.conf

Og før vi går videre, lad os oprette database pgpool og bruger pgpool i alle klynger (i min sandbox er de master, failover og slave, så jeg skal kun køre det på master):

t=# create database pgpool;
CREATE DATABASE
t=# create user pgpool;
CREATE ROLE

Til sidst - starter:

[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

Fantastisk - så vi kan fortsætte til den første funktion - lad os tjekke belastningsbalancering. Det har nogle krav, der skal bruges, understøtter hints (f.eks. at balancere i samme session), har sort-hvid-listede funktioner, har regulære udtryk baseret omdirigeringspræferenceliste. Det er sofistikeret. Ak, at gå grundigt over al den funktionalitet ville være uden for rammerne af denne blog, derfor vil vi tjekke de enkleste demoer:

Først vil noget meget simpelt vise, hvilken node der bruges til at vælge (i mit setup, master spins på 5400, slave på 5402 og failover på 5401, mens pgpool selv er på 5433, da jeg har en anden klynge kørende og ikke ønskede at blande sig med det):

[email protected]:~$ psql -h localhost -p 5433 t -c "select current_setting('port') from ts limit 1"
 current_setting
-----------------
 5400
(1 row)

Så 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

Store. Det afbalancerer bestemt belastningen mellem noder, men synes ikke at balancere lige meget - måske er det så smart, at det kender vægten af ​​hvert udsagn? Lad os tjekke fordelingen med forventede resultater:

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 analyserer ikke vægten af ​​udsagn - det var en DBA med hendes indstillinger igen! Indstillingerne (se lb_weight-attributten) stemmer overens med faktiske forespørgselsdestinationsmål. Du kan nemt ændre det (som vi gjorde her) ved at ændre den tilsvarende indstilling, f.eks.:

[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 Whitepaper Today PostgreSQL Management &Automation med ClusterControlFå flere oplysninger om, hvad du skal vide for at implementere, overvåge, administrere og skalere PostgreSQLDownload Whitepaper

Store! Den næste fantastiske funktion, der tilbydes, er forbindelsespooling. Med 3.5 løses "tornende flok-problemet" ved at serialisere accept()-kald, hvilket i høj grad fremskynder "klientforbindelsestiden". Og alligevel er denne funktion ret ligetil. Det tilbyder ikke flere niveauer af pooling eller flere puljer konfigureret til den samme database (pgpool lader dig vælge, hvor du vil køre selects med database_redirect_preference_list for belastningsbalancering), eller andre fleksible funktioner, der tilbydes af 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, sandt, jeg ændrede dem lavere end standard 32, så outputtet ikke ville tage flere sider. Så lad os prøve at overskride antallet af sessioner (nedenfor åbner jeg postgres-sessioner async in loop, så de 6 sessioner ville blive anmodet om mere eller mindre på samme tid):

[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 lader sessioner komme med tre - forventes, da en tages af ovenstående session (ved at vælge fra pg_stat_activity), så 4-1=3. Så snart pg_sleep er færdig med sin lur på et sekund, og sessionen er lukket af postgres, lukkes den næste ind. Så efter de første tre slutter, træder de næste tre ind. Hvad sker der med resten? De er i kø, indtil den næste forbindelsesplads frigøres. Derefter sker den proces, der er beskrevet ved siden af ​​serialize_accept, og klienten bliver forbundet.

Hvad? Bare session pooling i session mode? Er det det hele?.. Nej, her træder cachen ind! Se.:

postgres=# /*NO LOAD BALANCE*/ select 1;
 ?column?
----------
        1
(1 row)

Kontrollerer 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 derefter den første sætning igen og observer, at state_change ikke ændrer sig, hvilket betyder, at du ikke engang kommer til databasen for at få et kendt resultat! Selvfølgelig, hvis du sætter en funktion, der kan ændres, bliver resultaterne ikke cachelagret. Eksperimenter med:

postgres=# /*NO LOAD BALANCE*/ select 1, now();
 ?column? |             now
----------+------------------------------
        1 | 2018-04-10 13:35:44.41823+01
(1 row)

Du vil opdage, at state_change ændrer sig, ligesom resultatet.

Sidste punkt her - hvorfor /*NO LOAD BALANCE*/ ?.. for at være sikker tjekker vi pg_stat_activity på master og kører også forespørgsel på master. Det samme kan du bruge /*NO QUERY CACHE*/ tip for at undgå at få et cachelagret resultat.

Allerede meget for en kort anmeldelse? Men vi rørte ikke engang HA-delen! Og mange brugere ser mod pgpool specifikt for denne funktion. Nå, dette er ikke slutningen på historien, det er slutningen på første del. Del to kommer, hvor vi kort vil dække HA og nogle andre tips om brug af pgpool...


  1. Hvordan ændrer jeg min session til at vise UTF8 i Oracle?

  2. Pivotering, afpivotering og opdeling af kolonner i Power BI Query Editor

  3. Oracle SQL-forespørgsel til liste over alle skemaer i en DB

  4. Find alle forespørgsler, der bruger en bestemt tabel