PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Przewodnik po Pgpool dla PostgreSQL:część pierwsza

Pgpool jest dziś mniej aktualny niż 10 lat temu, kiedy był domyślną częścią konfiguracji produkcyjnej PostgreSQL. Często, gdy ktoś mówił o klastrze PostgreSQL, miał na myśli postgreSQL stojący za pgpool, a nie samą instancję PostgreSQL (co jest właściwym terminem). Pgpool jest rozpoznawany przez najbardziej wpływowych graczy Postgres:społeczność postgresql, wiersz poleceń, 2ndquadrant, EDB, citusdata, postgrespro (uporządkowane według wieku, a nie wpływów). Zdaję sobie sprawę, że poziom rozpoznawalności moich linków jest bardzo różny - chcę tylko podkreślić ogólny wpływ pgpool na świat postgres. Niektórzy z najbardziej znanych obecnych „dostawców” postgresu zostali znalezieni po tym, jak pgpool był już sławny. Więc co sprawia, że ​​jest tak sławny?

Tylko lista najbardziej pożądanych funkcji sprawia, że ​​wygląda świetnie:

  • natywna replikacja
  • zestawianie połączeń
  • równoważenie obciążenia dla skalowalności odczytu
  • wysoka dostępność (watchdog z wirtualnym adresem IP, odzyskiwanie online i przełączanie awaryjne)

Cóż, zróbmy piaskownicę i zagrajmy. Moja konfiguracja próbki to tryb master-slave. Przypuszczam, że jest to obecnie najbardziej popularne, ponieważ zazwyczaj używasz replikacji strumieniowej wraz z równoważeniem obciążenia. Obecnie tryb replikacji jest rzadko używany. Większość administratorów baz danych pomija to na rzecz replikacji strumieniowej i pglogicznej, a wcześniej slony.

Tryb replikacji ma wiele ciekawych ustawień i na pewno ciekawą funkcjonalność. Ale większość administratorów baz danych ma konfigurację master/multi slave, zanim dotrą do pgpool. Dlatego szukają automatycznego przełączania awaryjnego i równoważenia obciążenia, a pgpool oferuje go po wyjęciu z pudełka dla istniejących środowisk master/multi slave. Nie wspominając już o tym, że od Postgresa 9.4 replikacja strumieniowa działa bez większych błędów i obsługiwana jest replikacja z 10 indeksów haszujących, więc prawie nic nie stoi na przeszkodzie, aby z niej korzystać. Również replikacja strumieniowa jest domyślnie asynchroniczna (można ją skonfigurować do synchronicznych, a nawet „liniowych” skomplikowanych ustawień synchronizacji, podczas gdy natywna replikacja pgpool jest synchroniczna (co oznacza wolniejsze zmiany danych) bez opcji wyboru. Obowiązują również dodatkowe ograniczenia. Sam podręcznik Pgpool sugeruje, aby preferować jeśli to możliwe, replikacja strumieniowa przez natywny pgpool). A więc to jest mój wybór tutaj.

Ach, ale najpierw musimy go zainstalować - prawda?

Instalacja (wyższej wersji na Ubuntu).

Najpierw sprawdź wersję ubuntu za pomocą lsb_release -a. Dla mnie repozytorium to:

[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

Na koniec sama instalacja:

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

Konfiguracja:

Domyślna konfiguracja użytkownika z zalecanego trybu:

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

Rozpoczęcie:

Jeśli przegapiłeś konfigurację, zobaczysz:

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

Ach to prawda – mój zły, ale łatwy do naprawienia (możliwy do wykonania na ślepo za pomocą jednej wkładki, jeśli chcesz tego samego użytkownika do wszystkich kontroli stanu zdrowia i rekonwalescencji):

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

I zanim przejdziemy dalej, stwórzmy bazę danych pgpool i pgpool użytkownika we wszystkich klastrach (w mojej piaskownicy są to master, failover i slave, więc muszę uruchomić je tylko na master):

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

Nareszcie - zaczynając:

[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

Świetnie – więc możemy przejść do pierwszej funkcji – sprawdźmy równoważenie obciążenia. Ma pewne wymagania do wykorzystania, obsługuje podpowiedzi (np. do balansowania w tej samej sesji), posiada czarno-białą listę funkcji, ma listę preferencji przekierowań opartą na wyrażeniach regularnych. Jest wyrafinowany. Niestety, zagłębianie się w całą tę funkcjonalność wykraczałoby poza zakres tego bloga, dlatego sprawdzimy najprostsze wersje demonstracyjne:

Najpierw coś bardzo prostego pokaże, który węzeł jest używany do wyboru (w mojej konfiguracji master obraca się na 5400, slave na 5402 i przełączanie awaryjne na 5401, podczas gdy sam pgpool jest na 5433, ponieważ mam inny klaster uruchomiony i nie chciałem ingerować z nim):

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

Następnie w pętli:

[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

Świetny. Zdecydowanie równoważy obciążenie między węzłami, ale wydaje się, że nie równo - może jest tak sprytny, że zna wagę każdego stwierdzenia? Sprawdźmy rozkład z oczekiwanymi wynikami:

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)

Nie – pgpool nie analizuje wagi wyciągów – znowu był DBA z jej ustawieniami! Ustawienia (zobacz atrybut lb_weight) są zgodne z rzeczywistymi docelowymi miejscami docelowymi zapytania. Możesz to łatwo zmienić (tak jak to zrobiliśmy tutaj), zmieniając odpowiednie ustawienie, np.:

[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
Pobierz oficjalny dokument już dziś Zarządzanie i automatyzacja PostgreSQL za pomocą ClusterControlDowiedz się, co musisz wiedzieć, aby wdrażać, monitorować, zarządzać i skalować PostgreSQLPobierz oficjalny dokument

Świetny! Kolejną świetną oferowaną funkcją jest łączenie połączeń. W wersji 3.5 „gromujący problem stada” został rozwiązany przez serializację wywołań accept(), co znacznie przyspiesza czas „połączenia klienta”. A jednak ta funkcja jest dość prosta. Nie oferuje kilku poziomów pulowania ani kilku pul skonfigurowanych dla tej samej bazy danych (pgpool pozwala jednak wybrać, gdzie uruchomić wybory za pomocą database_redirect_preference_list równoważenia obciążenia) ani innych elastycznych funkcji oferowanych przez pgBouncer.

Tak krótkie 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)

Ach, prawda, zmieniłem je na niższe niż domyślne 32, więc dane wyjściowe nie zajęłyby kilku stron. Cóż, spróbujmy więc przekroczyć liczbę sesji (poniżej otwieram sesje postgres w pętli asynchronicznej, więc 6 sesji zostanie wymaganych mniej więcej w tym samym czasie):

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

Pozwala to na przyjście trzech sesji - oczekiwano, ponieważ jedna jest brana przez powyższą sesję (wybierając z pg_stat_activity), więc 4-1=3. Gdy tylko pg_sleep skończy swoją drugą drzemkę i sesja zostanie zamknięta przez postgres, wpuszczany jest następny. Więc po zakończeniu pierwszych trzech, wkraczają kolejne trzy. Co się dzieje z resztą? Są one umieszczane w kolejce do momentu zwolnienia następnego gniazda połączenia. Następnie następuje proces opisany obok serialize_accept i klient zostaje połączony.

Co? Tylko łączenie sesji w trybie sesji? Czy to wszystko?.. Nie, tutaj wkracza buforowanie! Spójrz:

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

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

Następnie uruchom ponownie pierwszą instrukcję i obserwuj, że state_change się nie zmienia, co oznacza, że ​​nawet nie dostajesz się do bazy danych, aby uzyskać znany wynik! Oczywiście, jeśli umieścisz funkcję mutowalną, wyniki nie zostaną zapisane w pamięci podręcznej. Eksperymentuj z:

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

Przekonasz się, że state_change zmienia się, podobnie jak wynik.

Ostatni punkt tutaj - dlaczego /*BRAK OBCIĄŻENIA BALANCE*/ ?..dla pewności sprawdzamy pg_stat_activity na masterze i uruchamiamy zapytanie również na masterze. To samo możesz użyć podpowiedzi /*NO QUERY CACHE*/, aby uniknąć uzyskania wyniku w pamięci podręcznej.

Już dużo za krótką recenzję? Ale nawet nie dotknęliśmy części HA! Wielu użytkowników patrzy na pgpool specjalnie dla tej funkcji. Cóż, to nie koniec historii, to koniec części pierwszej. Nadchodzi część druga, w której krótko omówimy HA i kilka innych wskazówek dotyczących korzystania z pgpool...


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Użyj \copy psql dla zapytania wielowierszowego

  2. Automatyzacja codziennych zadań PostgreSQL za pomocą Jenkins

  3. Postgres - jak zwrócić wiersze z liczbą 0 za brakujące dane?

  4. Wygeneruj SQL, aby zaktualizować klucz podstawowy

  5. Dołączanie (wypychanie) i usuwanie z tablicy JSON w PostgreSQL 9.5+