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

Pool di connessioni PostgreSQL con PgBouncer

Il pool di connessioni è un modo semplice ma efficace per migliorare le prestazioni delle tue app e ridurre il carico sui tuoi server PostgreSQL. Continua a leggere per saperne di più sull'utilizzo di PgBouncer per raggruppare le connessioni PostgreSQL.

Perché il pool di connessioni?

PostgreSQL ha un'architettura di gestione delle connessioni piuttosto pesante. Per ogni connessione in entrata, il postmaster (il principale demone di Postgres) esegue il fork di un nuovo processo (convenzionalmente chiamato backend ) per gestirlo. Sebbene questo design fornisca una migliore stabilità e isolamento, non lo rende particolarmente efficiente nella gestione di connessioni di breve durata. Una nuova connessione client Postgres comporta la configurazione del TCP, la creazione di processi e l'inizializzazione del back-end, tutti elementi costosi in termini di tempo e risorse di sistema.

Questo ovviamente è un problema solo se le connessioni vengono create troppo spesso e scartate senza essere riutilizzate. Sfortunatamente, non è raro avere un cluster di nodi Web che esegue applicazioni scritte in PHP o altri linguaggi simili che devono connettersi al database una volta per caricamento della pagina. Sono comuni anche lavori in batch che creano rapidamente un mucchio di connessioni in rapida successione. Utilizzo di connectionpooling in tali scenari può ridurre drasticamente il carico sul server PostgreSQL e migliorare notevolmente le latenze delle query.

Con il pool di connessioni, i client si connettono a un server proxy che mantiene un insieme di connessioni dirette al server PostgreSQL reale. In genere, i client non si rendono conto (e non devono) rendersi conto di essere connessi a un server proxy piuttosto che al server effettivo. Il proxy può essere eseguito sullo stesso nodo del client (ad esempio, su ciascun nodo Web), nel qual caso i client possono connettersi al proxy tramite socket di dominio Unix che hanno un sovraccarico di connessione molto basso. Anche se il proxy si trova su un altro nodo e il client necessita di una connessione TCP per raggiungere il proxy, è possibile evitare il sovraccarico di un nuovo backend Postgres.

Cos'è PgBouncer?

PgBouncer è un pooler di connessioni single-binary open source per PostgreSQL. Può raggruppare connessioni a uno o più database (su server possibilmente diversi) e servire client su socket di dominio TCP e Unix.

PgBouncer mantiene un pool di connessioni per ogni utente univoco, coppia di database. In genere è configurato per distribuire una di queste connessioni a una nuova connessione client in entrata e restituirla al pool quando il client si disconnette. È possibile configurare PgBouncer per eseguire il pool in modo più aggressivo, in modo che possa prelevare e restituire la connessione al pool in corrispondenza dei confini della transazione o dell'istruzione anziché ai limiti della connessione. Tuttavia, ci sono alcune conseguenze potenzialmente indesiderabili.

Dovresti essere in grado di installare PgBouncer con il gestore di pacchetti della tua distribuzione:

# RedHat/CentOS/..
$ sudo yum install pgbouncer

# Debian/Ubuntu/..
$ sudo apt-get install pgbouncer

È anche disponibile dai repository standard di Postgres APT e YUM, che possono essere utilizzati se i pacchetti della tua distribuzione sono vecchi o rotti.

PgBouncer si basa su un file di configurazione principale, generalmente archiviato come/etc/pgbouncer/pgbouncer.ini . Puoi invocare pgbouncer come servizio systemd, o semplicemente eseguirlo anche senza privilegi di superutente con il percorso di questo file di configurazione.

Per fare un giro, creiamo un database db1 e un utente user1 sul nostro server:

$ 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=#

I client si collegheranno al database db1 con il nome utente user1 epassword user1pass . Il nostro obiettivo è fare in modo che i client si connettano a PgBouncer, che invierà un proxy e unirà le connessioni al server effettivo.

Ora creiamo un file (ovunque) con questi contenuti:

[databases]
db1 = host=localhost dbname=db1

[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 16432
auth_file = userlist.txt

Dobbiamo anche creare un file “userlist.txt” nella stessa directory, con il nome utente e le password (con hash) degli utenti a cui PgBouncer permetterà di connettersi. Creare “userlist.txt” con i seguenti contenuti:

"user1" "md5638b81c77071ea624d1ad4adb1433540"

Il secondo valore è l'MD5 di “user1passuser1”, preceduto da “md5”. Questa è la solita convenzione di Postgres.

Ora iniziamo PgBouncer in primo piano:

$ /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

Ora abbiamo avviato un PgBouncer che è in ascolto sulla porta TCP 127.0.0.1 16432, così come sul socket del dominio Unix /tmp/.s.PGSQL.16432 . L'unico "database" disponibile su questo server proxy è db1 . L'unico utente che può connettersi a questo server è user1 . Proviamo a connetterci con 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=>

Il client (psql) si connette correttamente a localhost:16432, ma puoi vedere che la connessione viene effettivamente inviata tramite proxy a localhost:5432.

Puoi provare a disconnetterti e riconnetterti alcune volte, quindi controllare quante connessioni sono ancora presenti sul server effettivo:

postgres=# select count(*) from pg_stat_activity
postgres-#   where datname='db1' and usename='user1';
 count
-------
     1
(1 row)

PgBouncer non disconnetterà la connessione effettiva quando il client si disconnette. Puoi configurare le connessioni minime, massime e riservate che PgBouncer manterrà per ogni pool nel file di configurazione.

Distribuzione di PgBouncer

Dove installi ed esegui PgBouncer? Ci sono diverse risposte, con diversi vantaggi:

  • Sul nodo del server Postgres :puoi installarlo insieme al server PostgreSQL stesso, sullo stesso nodo. I client si connettono alla porta PgBouncer piuttosto che alla porta Postgres. Questo ha l'effetto di un Postgres "potenziato" che esegue internamente il pool di connessioni. Devi anche mantenere solo una copia dei file di configurazione per PgBouncer. D'altra parte, ciò comporta effettivamente l'esecuzione di qualcos'altro anche sul nodo del server PostgreSQL, che potrebbe non essere facile o consentito (firewall, policy) o addirittura possibile (AWSRDS).
  • Sui nodi client :puoi installare PgBouncer in ogni nodo client, ad esempio ogni nodo web esegue Apache e PHP e gli script PHP si connettono a localPgBouncer. Ciò ha il vantaggio di non dover disturbare la configurazione del server e la configurazione del pool può essere utilizzata per mantenere prevedibile il carico del server. D'altra parte, se il numero di nodi client è enorme o può variare molto a seconda del carico/ traffico, il server può essere sovraccaricato rapidamente.
  • Come cluster autonomo :la terza opzione per avere un cluster di nodi PgBouncer indipendenti e stateless, con a capo un bilanciatore del carico TCP come HAProxy. Questa configurazione, pur essendo più complicata delle altre due opzioni, fornisce il massimo controllo e configurabilità.

Amministrazione

PgBouncer consente agli utenti contrassegnati come amministratori di connettersi a un database virtuale chiamato "pgbouncer" ed emettere comandi per controllare il server e visualizzare le statistiche. Per provare questo, contrassegniamo prima "utente1" come amministratore modificando il file 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

Ora l'utente1 può connettersi al database denominato “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=#

Da qui, puoi eseguire varie operazioni come abilitare o disabilitare un determinato database, ispezionare e ricaricare la configurazione e altro ancora:

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)

Monitoraggio

Ci sono anche comandi per mostrare varie statistiche su PgBouncer, tra cui:

  • Statistiche per database sulla durata della query, il tempo di attesa del client, l'utilizzo della rete, il conteggio delle transazioni
  • Statistiche per pool sul numero di client attivi e in attesa, connessioni al server inattivo e utilizzato

Le statistiche vengono recuperate con i comandi in stile "MOSTRA xyz", come questo per recuperare le statistiche relative al pool:

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

Ulteriori letture

La home page di PgBouncer contiene maggiori dettagli su tutte le varie funzionalità e opzioni di configurazione di PgBouncer.

  • Pagina iniziale di PgBouncer
  • Repository GitHub PgBouncer
  • Postgres Wiki ha informazioni sul pool di connessioni
  • Pgpool è un'altra opzione per il pool di connessioni