No mundo do banco de dados, há muitos conceitos comuns, como alta disponibilidade, failover e pool de conexões. Todos eles são úteis para implementar em qualquer sistema, e até mesmo obrigatórios em alguns casos.
Um pool de conexões é um método de criar um pool de conexões e reutilizá-las evitando abrir novas conexões com o banco de dados o tempo todo, o que aumentará consideravelmente o desempenho de suas aplicações. O PgBouncer é um pool de conexões popular projetado para PostgreSQL, mas não é suficiente para atingir a Alta Disponibilidade do PostgreSQL por si só, pois não possui configuração de vários hosts, failover ou detecção.
Usar um Load Balancer é uma forma de ter Alta Disponibilidade em sua topologia de banco de dados. Pode ser útil para redirecionar o tráfego para nós de banco de dados íntegros, distribuir o tráfego entre vários servidores para melhorar o desempenho ou apenas para ter um único ponto de extremidade configurado em seu aplicativo para facilitar a configuração e o processo de failover. Para isso, o HAProxy é uma boa opção para complementar seu pool de conexões, pois é um proxy de código aberto que pode ser usado para implementar alta disponibilidade, balanceamento de carga e proxy para aplicativos baseados em TCP e HTTP.
Neste blog, usaremos os dois conceitos, balanceador de carga e pool de conexões (HAProxy + PgBouncer), para implantar um ambiente de alta disponibilidade para seu banco de dados PostgreSQL.
Como o PgBouncer funciona
O PgBouncer atua como um servidor PostgreSQL, então você só precisa acessar seu banco de dados usando as informações do PgBouncer (Endereço IP/Hostname e Porta), e o PgBouncer criará uma conexão com o servidor PostgreSQL, ou reutilize um se existir.
Quando o PgBouncer recebe uma conexão, ele realiza a autenticação, que depende do método especificado no arquivo de configuração. O PgBouncer suporta todos os mecanismos de autenticação que o servidor PostgreSQL suporta. Depois disso, o PgBouncer verifica se há uma conexão em cache, com a mesma combinação de nome de usuário + banco de dados. Se uma conexão em cache for encontrada, ele retorna a conexão ao cliente, caso contrário, cria uma nova conexão. Dependendo da configuração do PgBouncer e do número de conexões ativas, pode ser possível que a nova conexão seja enfileirada até que possa ser criada, ou mesmo abortada.
O comportamento do PgBouncer depende do modo de pool configurado:
- pool de sessões (padrão):Quando um cliente se conecta, uma conexão de servidor será atribuída a ele durante todo o tempo em que o cliente permanecer conectado. Quando o cliente se desconectar, a conexão do servidor será colocada de volta no pool.
- pool de transações :Uma conexão de servidor é atribuída a um cliente somente durante uma transação. Quando o PgBouncer perceber que a transação terminou, a conexão do servidor será colocada de volta no pool.
- conjunto de instruções :A conexão do servidor será colocada de volta no pool imediatamente após a conclusão de uma consulta. As transações com vários extratos não são permitidas nesse modo, pois seriam interrompidas.
Para equilibrar as consultas entre vários servidores, no lado do PgBouncer, pode ser uma boa ideia diminuir o server_lifetime e também ativar o server_round_robin. Por padrão, as conexões inativas são reutilizadas pelo algoritmo LIFO, que pode não funcionar tão bem quando um balanceador de carga é usado.
Como instalar o PgBouncer
Vamos supor que você tenha o cluster PostgreSQL e o HAProxy implantados e ele esteja funcionando, caso contrário, você pode seguir esta postagem do blog para implantar facilmente o PostgreSQL para alta disponibilidade.
Você pode instalar o PgBouncer em cada nó do banco de dados ou em uma máquina externa, em qualquer caso, você terá algo assim:
Para obter o software PgBouncer, você pode ir para a seção de download do PgBouncer, ou use os repositórios RPM ou DEB. Para este exemplo, usaremos o CentOS 8 e o instalaremos a partir do repositório oficial do PostgreSQL.
Primeiro, baixe e instale o repositório correspondente do site PostgreSQL (caso ainda não o tenha instalado):
$ wget https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm
$ rpm -Uvh pgdg-redhat-repo-latest.noarch.rpm
Em seguida, instale o pacote PgBouncer:
$ yum install pgbouncer
Verifique a instalação:
$ pgbouncer --version
PgBouncer 1.14.0
libevent 2.1.8-stable
adns: c-ares 1.13.0
tls: OpenSSL 1.1.1c FIPS 28 May 2019
Quando estiver concluído, você terá um novo arquivo de configuração localizado em /etc/pgbouncer/pgbouncer.ini:
[databases]
[users]
[pgbouncer]
logfile = /var/log/pgbouncer/pgbouncer.log
pidfile = /var/run/pgbouncer/pgbouncer.pid
listen_addr = 127.0.0.1
listen_port = 6432
auth_type = trust
auth_file = /etc/pgbouncer/userlist.txt
admin_users = postgres
stats_users = stats, postgres
Vamos ver esses parâmetros um por um:
- Seção de bancos de dados [bancos de dados]: Este contém pares chave=valor onde a chave será tomada como um nome de banco de dados e o valor como uma lista de estilo de string de conexão libpq de pares chave=valor.
- Seção de usuário [usuários]: Este contém pares chave=valor onde a chave será tomada como um nome de usuário e o valor como uma lista de estilo de string de conexão libpq de pares chave=valor de definições de configuração específicas para este usuário.
- arquivo de registro :especifica o arquivo de log. O arquivo de log é mantido aberto, portanto, após a rotação, mate -HUP ou no console RELOAD; deve ser feito.
- pidfile :Especifica o arquivo PID. Sem o conjunto pidfile, o daemon não é permitido.
- listen_addr :especifica uma lista de endereços onde escutar conexões TCP. Você também pode usar * significando “ouvir em todos os endereços”. Quando não definido, somente conexões de soquete Unix são aceitas.
- listen_port: Em qual porta escutar. Aplica-se a soquetes TCP e Unix. A porta padrão é 6432.
- auth_type: Como autenticar usuários.
- auth_file :O nome do arquivo para carregar nomes de usuário e senhas.
- admin_users :lista separada por vírgulas de usuários de banco de dados que têm permissão para conectar e executar todos os comandos no console.
- stats_users :lista separada por vírgulas de usuários de banco de dados que têm permissão para se conectar e executar consultas somente leitura no console.
Esta é apenas uma amostra do arquivo de configuração padrão, pois o original tem 359 linhas, mas o restante das linhas é comentado por padrão. Para obter todos os parâmetros disponíveis, você pode verificar a documentação oficial.
Como usar o PgBouncer
Agora, vamos ver uma configuração básica para que funcione.
O arquivo de configuração pgbouncer.ini:
$ cat /etc/pgbouncer/pgbouncer.ini
[databases]
world = host=127.0.0.1 port=5432 dbname=world
[pgbouncer]
logfile = /var/log/pgbouncer/pgbouncer.log
pidfile = /var/run/pgbouncer/pgbouncer.pid
listen_addr = *
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
admin_users = admindb
E o arquivo de autenticação:
$ cat /etc/pgbouncer/userlist.txt
"admindb" "root123"
Então, neste caso, instalei o PgBouncer no mesmo nó do banco de dados, escutando todos os endereços IP, e ele se conecta a um banco de dados PostgreSQL chamado “world”. Também estou gerenciando os usuários permitidos no arquivo userlist.txt com uma senha de texto simples que pode ser criptografada, se necessário.
Para iniciar o serviço PgBouncer, basta executar o seguinte comando:
$ pgbouncer -d /etc/pgbouncer/pgbouncer.ini
Onde -d significa “daemon”, então ele será executado em segundo plano.
$ netstat -pltn
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:6432 0.0.0.0:* LISTEN 4274/pgbouncer
tcp6 0 0 :::6432 :::* LISTEN 4274/pgbouncer
Como você pode ver, o PgBouncer está ativo e aguardando conexões na porta 6432. Para acessar o banco de dados PostgreSQL, execute o seguinte comando usando suas informações locais (porta, host, nome de usuário e nome do banco de dados) :
$ psql -p 6432 -h 127.0.0.1 -U admindb world
Password for user admindb:
psql (12.4)
Type "help" for help.
world=#
Lembre-se de que o nome do banco de dados (world) é o banco de dados configurado em seu arquivo de configuração do PgBouncer:
[databases]
world = host=127.0.0.1 port=5432 dbname=world
Monitorando e gerenciando o PgBouncer
Em vez de acessar seu banco de dados PostgreSQL, você pode se conectar diretamente ao PgBouncer para gerenciá-lo ou monitorá-lo. Para isso, use o mesmo comando que você usou anteriormente, mas altere o banco de dados para “pgbouncer”:
$ psql -p 6432 -h 127.0.0.1 -U admindb pgbouncer
Password for user admindb:
psql (12.4, server 1.14.0/bouncer)
Type "help" for help.
pgbouncer=# SHOW HELP;
NOTICE: Console usage
DETAIL:
SHOW HELP|CONFIG|DATABASES|POOLS|CLIENTS|SERVERS|USERS|VERSION
SHOW FDS|SOCKETS|ACTIVE_SOCKETS|LISTS|MEM
SHOW DNS_HOSTS|DNS_ZONES
SHOW STATS|STATS_TOTALS|STATS_AVERAGES|TOTALS
SET key = arg
RELOAD
PAUSE [<db>]
RESUME [<db>]
DISABLE <db>
ENABLE <db>
RECONNECT [<db>]
KILL <db>
SUSPEND
SHUTDOWN
SHOW
Agora, você pode executar diferentes comandos do PgBouncer para monitorá-lo:
MOSTRAR STATS_TOTALS:
pgbouncer=# SHOW STATS_TOTALS;
database | xact_count | query_count | bytes_received | bytes_sent | xact_time | query_time | wait_time
-----------+------------+-------------+----------------+------------+-----------+------------+-----------
pgbouncer | 1 | 1 | 0 | 0 | 0 | 0 | 0
world | 2 | 2 | 59 | 234205 | 8351 | 8351 | 4828
(2 rows)
MOSTRAR SERVIDORES:
pgbouncer=# SHOW SERVERS;
type | user | database | state | addr | port | local_addr | local_port | connect_time | request_time
| wait | wait_us | close_needed | ptr | link | remote_pid | tls
------+---------+----------+--------+-----------+------+------------+------------+-------------------------+-------------------------
+------+---------+--------------+----------------+----------------+------------+-----
S | admindb | world | active | 127.0.0.1 | 5432 | 127.0.0.1 | 45052 | 2020-09-09 18:31:57 UTC | 2020-09-09 18:32:04 UTC
| 0 | 0 | 0 | 0x55b04a51b3d0 | 0x55b04a514810 | 5738 |
(1 row)
MOSTRAR CLIENTES:
pgbouncer=# SHOW CLIENTS;
type | user | database | state | addr | port | local_addr | local_port | connect_time | request_time
| wait | wait_us | close_needed | ptr | link | remote_pid | tls
------+---------+-----------+--------+-----------+-------+------------+------------+-------------------------+-----------------------
--+------+---------+--------------+----------------+----------------+------------+-----
C | admindb | pgbouncer | active | 127.0.0.1 | 46950 | 127.0.0.1 | 6432 | 2020-09-09 18:29:46 UTC | 2020-09-09 18:55:11 UT
C | 1441 | 855140 | 0 | 0x55b04a5145e0 | | 0 |
C | admindb | world | active | 127.0.0.1 | 47710 | 127.0.0.1 | 6432 | 2020-09-09 18:31:41 UTC | 2020-09-09 18:32:04 UT
C | 0 | 0 | 0 | 0x55b04a514810 | 0x55b04a51b3d0 | 0 |
(2 rows)
MOSTRAR PISCINAS:
pgbouncer=# SHOW POOLS;
database | user | cl_active | cl_waiting | sv_active | sv_idle | sv_used | sv_tested | sv_login | maxwait | maxwait_us | pool_
mode
-----------+-----------+-----------+------------+-----------+---------+---------+-----------+----------+---------+------------+------
-----
pgbouncer | pgbouncer | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | state
ment
world | admindb | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | sessi
on
(2 rows)
E para gerenciá-lo...
RECARREGAR:
pgbouncer=# RELOAD;
RELOAD
PAUSA:
pgbouncer=# PAUSE world;
PAUSE
RESUMO:
pgbouncer=# RESUME world;
RESUME
Esses comandos são apenas um exemplo. Para obter uma lista completa de comandos, consulte a documentação oficial.
Conclusão
Usar uma combinação de PgBouncer + HAProxy + PostgreSQL é uma boa maneira de obter alta disponibilidade para seu cluster PostgreSQL, melhorando o desempenho do banco de dados ao mesmo tempo.
Como você pode ver, se você tiver seu ambiente PostgreSQL instalado, que pode ser implantado usando o ClusterControl em apenas alguns cliques, poderá adicionar facilmente o PgBouncer para aproveitar a vantagem de ter um pool de conexões para seus sistemas.