Пулирането на връзки е прост, но ефективен начин за подобряване на производителността на вашите приложения и намаляване на натоварването на вашите PostgreSQL сървъри. Прочетете, за да научите повече за използването на PgBouncer за обединяване на PostgreSQL връзки.
Защо пул на връзки?
PostgreSQL има доста тежка архитектура за обработка на връзки. За всяка входяща връзка пощенският администратор (основният Postgres демон) разклонява нов процес (условно наричан бекенд ), за да се справя. Въпреки че този дизайн осигурява по-добра стабилност и изолация, това не го прави особено ефективен при работа с краткотрайни връзки. Нова клиентска връзка на Postgres включва настройка на TCP, създаване на процес и инициализация на бекенда – всичко това е скъпо по отношение на време и системни ресурси.
Това разбира се е проблем само ако връзките се създават твърде често и се изхвърлят без повторна употреба. За съжаление, не е необичайно да имате клъстер от уеб възли, изпълняващи приложения, написани на PHP или други подобни езици, които трябва да се свързват с базата данни веднъж на зареждане на страница. Пакетни задачи, които бързо правят множество връзки в бърза последователност, също са често срещани. Използване на обединяване на връзки в такива сценарии може драстично да намали натоварването на вашия PostgreSQLserver и драстично да подобри забавянето на заявката.
С пул на връзки, клиентите се свързват с прокси сървър, който поддържа набор от директни връзки към истинския PostgreSQL сървър. Обикновено клиентите не осъзнават (и не трябва) да осъзнават, че са свързани към прокси сървър, а не към действителния сървър. Проксито може да работи на същия възел като клиента (пример, на всеки уеб възел), в който случай клиентите могат да се свържат с прокси чрез сокети на Unix домейн, които имат много ниски разходи за връзка. Дори ако проксито е на друг възел и клиентът се нуждае от TCP връзка, за да достигне до проксито, режийните разходи за нов бекенд на Postgres могат да бъдат избегнати.
Какво е PgBouncer?
PgBouncer е пулър с отворен код, лек, единичен двоичен пул за връзка за PostgreSQL. Той може да обединява връзки към една или повече бази данни (на евентуално различни сървъри) и да обслужва клиенти през TCP и Unix домейн сокети.
PgBouncer поддържа пул от връзки за всеки уникален потребител, чифт база данни. Обикновено е конфигуриран да раздава една от тези връзки към нова входяща клиентска връзка и да я връща обратно в пула, когато клиентът прекъсне връзката. Можете да конфигурирате PgBouncer да обединява по-агресивно, така че да може да вземе и върне връзката към пула на границите на транзакция или оператор, а не на границите на връзката. За тях обаче има някои потенциално нежелани последствия.
Трябва да можете да инсталирате PgBouncer с мениджъра на пакети на вашата дистрибуция:
# RedHat/CentOS/..
$ sudo yum install pgbouncer
# Debian/Ubuntu/..
$ sudo apt-get install pgbouncer
Предлага се и от стандартните репозитории на Postgres APT и YUM, които могат да се използват, ако пакетите на вашата дистрибуция са стари или повредени.
PgBouncer разчита на основен конфигурационен файл, който обикновено се съхранява като/etc/pgbouncer/pgbouncer.ini
. Можете да извикате pgbouncer като systemd услуга или просто да я стартирате дори без права на суперпотребител с пътя до този конфигурационен файл.
За да го завъртим, нека създадем база данни db1 и потребител user1 на нашия сървър:
$ sudo -u postgres psql
psql (10.6 (Debian 10.6-1.pgdg90+1))
Type "help" for help.
postgres=# create user user1 password 'user1pass';
CREATE ROLE
postgres=# create database db1 owner user1;
CREATE DATABASE
postgres=#
Клиентите ще се свържат с базата данни db1
с потребителско име user1
и парола user1pass
. Нашата цел е да накараме клиентите да се свържат с PgBouncer, който ще прокси и обединява връзките към действителния сървър.
Сега нека създадем файл (навсякъде) с това съдържание:
[databases]
db1 = host=localhost dbname=db1
[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 16432
auth_file = userlist.txt
Също така трябва да създадем файл „userlist.txt“ в същата директория, с потребителско име и (хеширани) пароли на потребителите, които PgBouncer ще позволи да се свържат. Създайте „userlist.txt“ със следното съдържание:
"user1" "md5638b81c77071ea624d1ad4adb1433540"
Втората стойност е MD5 на „user1passuser1“, с префикс „md5“. Това е обичайната конвенция на Postgres.
Сега нека стартираме PgBouncer на преден план:
$ /usr/sbin/pgbouncer pgbouncer.ini
2019-02-05 11:46:18.011 10033 LOG file descriptor limit: 1024 (H:1048576), max_client_conn: 100, max fds possible: 130
2019-02-05 11:46:18.012 10033 LOG listening on 127.0.0.1:16432
2019-02-05 11:46:18.013 10033 LOG listening on unix:/tmp/.s.PGSQL.16432
2019-02-05 11:46:18.014 10033 LOG process up: pgbouncer 1.9.0, libevent 2.0.21-stable (epoll), adns: c-ares 1.12.0, tls: OpenSSL 1.1.0j 20 Nov 2018
Вече стартирахме PgBouncer, който слуша на 127.0.0.1 TCP порт 16432, както и на Unix домейн сокет /tmp/.s.PGSQL.16432
. Единствената „база данни“, налична на този прокси сървър, е db1
. Единственият потребител, който може да се свърже с този сървър, е user1
. Нека опитаме да се свържем с psql
:
$ psql -U user1 -p 16432 -h localhost db1
Password for user user1:
psql (10.6 (Debian 10.6-1.pgdg90+1))
Type "help" for help.
db1=> select inet_server_addr(), inet_server_port();
inet_server_addr | inet_server_port
------------------+------------------
127.0.0.1 | 5432
(1 row)
db1=>
Клиентът (psql) се свързва успешно с localhost:16432, но можете да видите, че връзката всъщност се проксира към localhost:5432.
Можете да опитате да прекъснете връзката и да се свържете отново няколко пъти, след което да проверите колко връзки все още има на действителния сървър:
postgres=# select count(*) from pg_stat_activity
postgres-# where datname='db1' and usename='user1';
count
-------
1
(1 row)
PgBouncer няма да прекрати действителната връзка, когато клиентът прекъсне връзката. Можете да конфигурирате минималните, максималните и запазените връзки, които PgBouncer ще поддържа за всеки пул в конфигурационния файл.
Внедряване на PgBouncer
Къде инсталирате и стартирате PgBouncer? Има различни отговори, с различни предимства:
- На възела на Postgres сървър :Можете да го инсталирате заедно със самия PostgreSQLserver, на същия възел. Клиентите се свързват към PgBouncer, а не към порта на Postgres. Това има ефект на „подобрен“ Postgres, който вътрешно обединява връзки. Вие също трябва да поддържате само едно копие на конфигурационните файлове за PgBouncer. От друга страна, това включва действително изпълнение на нещо друго също на възела на PostgreSQL сървъра, което може да не е лесно или разрешено (защитни стени, политики) или дори възможно (AWSRDS).
- На клиентски възли :Можете да инсталирате PgBouncer във всеки клиентски възел, например всеки уеб възел изпълнява Apache и PHP, а PHP скриптовете се свързват с localPgBouncer. Това има предимството, че не се налага да нарушава настройката на сървъра, а конфигурацията на пула може да се използва за поддържане на натоварването на сървъра предвидимо. От друга страна, ако броят на клиентските възли е огромен или може да варира много в зависимост от натоварването/ трафик, сървърът може бързо да се претовари.
- Като самостоятелен клъстер :Третата опция да имате клъстер от независими PgBouncer възли без състояние, предствани от TCP балансьор на натоварване като HAProxy. Тази настройка, макар и по-сложна от другите две опции, осигурява максимален контрол и възможност за конфигуриране.
Администриране
PgBouncer позволява на потребителите, маркирани като администратори, да се свързват с виртуална база данни, наречена „pgbouncer“ и да издават команди за управление на сървъра и виждане на статистика. За да опитате това, нека първо отбележим „user1“ като администратор, като променим файла pgbouncer.ini:
[databases]
db1 = host=localhost dbname=db1
[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 16432
auth_file = userlist.txt
admin_users = user1
Сега user1 може да се свърже с базата данни, наречена „pgbouncer“:
$ psql -U user1 -p 16432 -h localhost pgbouncer
Password for user user1:
psql (10.6 (Debian 10.6-1.pgdg90+1), server 1.9.0/bouncer)
Type "help" for help.
pgbouncer=#
От тук можете да правите различни неща като активиране или деактивиране на конкретна база данни, проверка и презареждане на конфигурацията и други:
pgbouncer=# RELOAD;
RELOAD
pgbouncer=# DISABLE db1;
DISABLE
pgbouncer=# ENABLE db1;
ENABLE
pgbouncer=# SHOW FDS;
fd | task | user | database | addr | port | cancel | link | client_encoding | std_strings | datestyle | timezone | pa
----+--------+-------+----------+-----------+-------+----------------+------+-----------------+-------------+-----------+-----------+---
6 | pooler | | | 127.0.0.1 | 16432 | 0 | 0 | | | | |
7 | pooler | | | unix | 16432 | 0 | 0 | | | | |
9 | server | user1 | db1 | 127.0.0.1 | 5432 | 45404395804679 | 0 | UTF8 | on | ISO, MDY | localtime |
(3 rows)
Мониторинг
Има също така команди за показване на различни статистически данни за PgBouncer, включително:
- Статистически данни за база данни относно продължителността на заявката, времето за изчакване на клиента, използването на мрежата, броя на транзакциите
- Статистика на пул за броя на активните и чакащи клиенти, неактивни и използвани сървърни връзки
Статистическите данни се извличат с команди в стил „SHOW xyz“, като тази за извличане на статистика, свързана с пул:
pgbouncer=# SHOW POOLS;
-[ RECORD 1 ]---------
database | db1
user | user1
cl_active | 0
cl_waiting | 0
sv_active | 0
sv_idle | 0
sv_used | 1
sv_tested | 0
sv_login | 0
maxwait | 0
maxwait_us | 0
pool_mode | session
-[ RECORD 2 ]---------
database | pgbouncer
user | pgbouncer
cl_active | 1
cl_waiting | 0
sv_active | 0
sv_idle | 0
sv_used | 0
sv_tested | 0
sv_login | 0
maxwait | 0
maxwait_us | 0
pool_mode | statement
Допълнително четене
Началната страница на PgBouncer съдържа повече подробности за всички различни функции и опции за конфигурация на PgBouncer.
- Начална страница на PgBouncer
- PgBouncer GitHub хранилище
- Postgres Wiki има информация за обединяване на връзки
- Pgpool е друга опция за обединяване на връзки