PgBouncer

Опубликовано – 22.12.2020

Очередная противозабывательная заметка. Как обычно, всё начинается с того, что архитектура системы отсутствует, нагрузка возрастает, пользователи жалуются. Сервер PostgreSQL перестает справляться с нагрузкой, надо срочно подпереть костылём.

Возникает логичное(на взгляд инфраструктуры) желание отправить все SELECT на мастер и реплику, а все остальные запросы только на мастер. Попутно прочитано про мультиплексор PgBouncer, сразу ясно, что такой хорошей вещью хуже не сделаешь.

Итак, делаем такую схему(элементы отказоустойчивости не отображаем):

У нас есть сервер приложений, которые отправляет запросы на pgbouncer. Со стороны приложения это будут запросы к двум разным базам, находящимся на одном адресе и порту.

Далее, pgbouncer отправляет запросы на haproxy, при этом порты баз отличаются.

Haproxy, в свою очередь, имеет две разные точки балансировки, отправляя запросы непосредственно к базам данных.

Вопросы установки haproxy и pgbouncer оставим за скобками, приведу только файлы конфигурации.

Haproxy:

global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
        ssl-default-bind-options no-sslv3

defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

# Connections to port 5432
listen Master
    bind *:5433
    mode tcp
    #mode http
    option pgsql-check user pgbouncer
    default-server inter 3s fall 3
    server master 10.10.10.10:5432 maxconn 500 check port 5432

# Connections to port 5433
listen Replica
    bind *:5432
    mode tcp
    option pgsql-check user pgbouncer
    default-server inter 3s fall 3
    server master 10.10.10.10:5432 maxconn 500 check port 5432
    server replica 10.10.10.20:5432 maxconn 500 check port 5432


listen stats
        mode http
        bind 10.10.10.30:8080
        log         localhost   local1  #debug
        log-tag stats
        option dontlognull
        option dontlog-normal

        stats enable
        stats show-node PGBouncer-Proxy
        stats show-desc "service for balance PostgreSQL session"
        stats uri /
        stats hide-version
        stats refresh 5s
        stats show-legends

Для работы pgsql-check нам необходимо иметь пользователя в базе, который будет проходить первый этап создания подключения (проверка наличия подходящей записи в pg_hba.conf). Создателями haproxy считается необходимым и достаточным этого для определения доступности СУБД и готовности ее к приему подключений. Так как нам потребуется пользователь для pgbouncer то выполняем на мастере:

#vi /etc/postgresql/10/our_cluster/pg_hba.conf

# PGBouncer
host pgbouncer pgbouncer 10.10.10.30/32 md5

#psql -p 5432 -U postgres
create user pgbouncer with password 'pgbouncer';
select * from pg_shadow;
select pg_reload_conf();

В качестве базы для пользователя pgbouncer указываем несуществующую базу, это предотвратит его подключения в СУБД. Нам надо скопировать строчку с md5 пользователя pgbouncer, она нам пригодится в дальнейшем.

Конфигурация pgbouncer выглядит следующим образом:

[databases]
master = host=10.10.10.30 port=5432 dbname=dvdrental auth_user=postgres
replica = host=10.10.10.30 port=5433 dbname=dvdrental auth_user=postgres

[pgbouncer]

logfile = /var/log/postgresql/pgbouncer.log
pidfile = /var/run/postgresql/pgbouncer.pid

listen_addr = 10.10.10.40
listen_port = 6432

unix_socket_dir = /var/run/postgresql

auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt

admin_users = pgbouncer
stats_users = pgbouncer

pool_mode = transaction

server_reset_query = DISCARD ALL

# Тестировать доступность сервера раз в 3600 секунд
server_check_query = select 1
server_check_delay = 3600 

# Общее число клиентов, которые могут подключиться (если все коннекты от одного пользователя, ставим больше max_user_connections).
max_client_conn = 500 

# Сколько дополнительных процессов может создать подключившийся пользователь
default_pool_size = 20 

# Если выбрали пул, можем подключить еще 5 сверху
reserve_pool_size = 5 

# Если клиент ждет больше 5 секунд, используем резерв
reserve_pool_timeout = 5 

# Сколько вообще возможно коннектов к базе (должно коррелировать с настройками PostgreSQL)
max_db_connections = 200
# Лимит подключений от одного юзера ко всем базам (если ходят от одного пользователя ко всем базам, то ориентируемся на max_db_connections и число баз)
max_user_connections = 400

# Переиспользуем коннекты по методу FIFO
server_round_robin = 1 

В нашем примере dvdrental — имя нашей базы данных. В файл /etc/pgbouncer/userlist.txt прописываем имя и хэш пользователя pgbouncer

"pgbouncer" "7d6a64110c600b34f0caa8385dd3847d"

Вот и все, проверяем:

#/usr/bin/psql -h 10.10.10.40 -p6432 -U ouruser master -c "SELECT 1;"
#/usr/bin/psql -h 10.10.10.40 -p6432 -U ouruser replica -c "SELECT 1;"

Насколько я понял, настройки pgbouncer подбираются под каждую базу.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

*