Nel mondo dei database, ci sono molti concetti comuni come High Availability, Failover e Connection pooling. Sono tutte cose utili da implementare su qualsiasi sistema e in alcuni casi anche indispensabili.
Un pool di connessioni è un metodo per creare un pool di connessioni e riutilizzarle evitando di aprire continuamente nuove connessioni al database, il che aumenterà considerevolmente le prestazioni delle tue applicazioni. PgBouncer è un popolare pool di connessioni progettato per PostgreSQL, ma non è sufficiente per ottenere l'elevata disponibilità di PostgreSQL da solo in quanto non dispone di configurazione, failover o rilevamento multi-host.
L'utilizzo di un sistema di bilanciamento del carico è un modo per avere un'elevata disponibilità nella topologia del database. Potrebbe essere utile per reindirizzare il traffico a nodi di database integri, distribuire il traffico su più server per migliorare le prestazioni o semplicemente per avere un singolo endpoint configurato nell'applicazione per una configurazione più semplice e un processo di failover. Per questo, HAProxy è una buona opzione per completare il pool di connessioni, in quanto è un proxy open source che può essere utilizzato per implementare alta disponibilità, bilanciamento del carico e proxy per applicazioni basate su TCP e HTTP.
In questo blog, utilizzeremo entrambi i concetti, Load Balancer e Connection pooling (HAProxy + PgBouncer), per distribuire un ambiente ad alta disponibilità per il tuo database PostgreSQL.
Come funziona PgBouncer
PgBouncer funge da server PostgreSQL, quindi è sufficiente accedere al database utilizzando le informazioni PgBouncer (Indirizzo IP/Nome host e porta) e PgBouncer creerà una connessione al server PostgreSQL, altrimenti riutilizzane uno se esiste.
Quando PgBouncer riceve una connessione, esegue l'autenticazione, che dipende dal metodo specificato nel file di configurazione. PgBouncer supporta tutti i meccanismi di autenticazione supportati dal server PostgreSQL. Successivamente, PgBouncer verifica la presenza di una connessione memorizzata nella cache, con la stessa combinazione nome utente + database. Se viene trovata una connessione memorizzata nella cache, restituisce la connessione al client, in caso contrario crea una nuova connessione. A seconda della configurazione di PgBouncer e del numero di connessioni attive, potrebbe essere possibile che la nuova connessione venga accodata fino a quando non può essere creata, o addirittura interrotta.
Il comportamento di PgBouncer dipende dalla modalità di pooling configurata:
- pooling di sessioni (impostazione predefinita):quando un client si connette, gli verrà assegnata una connessione al server per l'intera durata della connessione del client. Quando il client si disconnette, la connessione al server verrà rimessa nel pool.
- pool di transazioni :una connessione server viene assegnata a un client solo durante una transazione. Quando PgBouncer si accorge che la transazione è terminata, la connessione al server verrà rimessa nel pool.
- gruppo di dichiarazioni :la connessione al server verrà ripristinata nel pool subito dopo il completamento di una query. Le transazioni con più estratti conto non sono consentite in questa modalità poiché si interromperebbero.
Per bilanciare le query tra più server, sul lato PgBouncer, potrebbe essere una buona idea ridurre server_lifetime e anche attivare server_round_robin. Per impostazione predefinita, le connessioni inattive vengono riutilizzate dall'algoritmo LIFO, che potrebbe non funzionare molto bene quando viene utilizzato un bilanciamento del carico.
Come installare PgBouncer
Supponiamo che tu abbia distribuito il tuo cluster PostgreSQL e HAProxy e che sia attivo e funzionante, altrimenti puoi seguire questo post del blog per distribuire facilmente PostgreSQL per l'alta disponibilità.
Puoi installare PgBouncer su ogni nodo del database o su una macchina esterna, in ogni caso avrai qualcosa del genere:
Per ottenere il software PgBouncer puoi andare nella sezione download di PgBouncer, oppure utilizzare i repository RPM o DEB. Per questo esempio, utilizzeremo CentOS 8 e lo installeremo dal repository PostgreSQL ufficiale.
Per prima cosa, scarica e installa il repository corrispondente dal sito PostgreSQL (se non lo hai ancora installato):
$ 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
Quindi, installa il pacchetto PgBouncer:
$ yum install pgbouncer
Verifica l'installazione:
$ 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
Al termine, avrai un nuovo file di configurazione che si trova in /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
Vediamo questi parametri uno per uno:
- Sezione database [database]: Questo contiene coppie chiave=valore in cui la chiave verrà presa come nome del database e il valore come un elenco di stili di stringa di connessione libpq di coppie chiave=valore.
- Sezione utente [utenti]: Questo contiene coppie chiave=valore in cui la chiave verrà presa come nome utente e il valore come un elenco di stili di stringa di connessione libpq di coppie chiave=valore di impostazioni di configurazione specifiche per questo utente.
- file di registro :specifica il file di registro. Il file di registro viene mantenuto aperto, quindi dopo la rotazione kill -HUP o su console RELOAD; dovrebbe essere fatto.
- pidfile :Specifica il file PID. Senza il file pid impostato, il demone non è consentito.
- ascolta_addr :specifica un elenco di indirizzi in cui ascoltare le connessioni TCP. Puoi anche usare * che significa "ascolta su tutti gli indirizzi". Quando non è impostato, sono accettate solo connessioni socket Unix.
- listen_port: Su quale porta ascoltare. Si applica a socket TCP e Unix. La porta predefinita è 6432.
- auth_type: Come autenticare gli utenti.
- file_auth :il nome del file da cui caricare nomi utente e password.
- admin_users :elenco separato da virgole di utenti del database autorizzati a connettersi ed eseguire tutti i comandi sulla console.
- stats_users :elenco separato da virgole di utenti del database autorizzati a connettersi ed eseguire query di sola lettura sulla console.
Questo è solo un esempio del file di configurazione predefinito, poiché l'originale ha 359 righe, ma il resto delle righe è commentato per impostazione predefinita. Per ottenere tutti i parametri disponibili, puoi consultare la documentazione ufficiale.
Come usare PgBouncer
Ora, vediamo una configurazione di base per farlo funzionare.
Il file di configurazione 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 il file di autenticazione:
$ cat /etc/pgbouncer/userlist.txt
"admindb" "root123"
Quindi, in questo caso, ho installato PgBouncer nello stesso nodo del database, ascoltando tutti gli indirizzi IP, e si connette a un database PostgreSQL chiamato "world". Gestisco anche gli utenti consentiti nel file userlist.txt con una password in testo semplice che può essere crittografata se necessario.
Per avviare il servizio PgBouncer è sufficiente eseguire il seguente comando:
$ pgbouncer -d /etc/pgbouncer/pgbouncer.ini
Dove -d significa "demone", quindi verrà eseguito in background.
$ 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
Come puoi vedere, PgBouncer è attivo e in attesa di connessioni nella porta 6432. Per accedere al database PostgreSQL, esegui il seguente comando usando le tue informazioni locali (porta, host, nome utente e nome del database) :
$ psql -p 6432 -h 127.0.0.1 -U admindb world
Password for user admindb:
psql (12.4)
Type "help" for help.
world=#
Tieni presente che il nome del database (world) è il database configurato nel tuo file di configurazione di PgBouncer:
[databases]
world = host=127.0.0.1 port=5432 dbname=world
Monitoraggio e gestione di PgBouncer
Invece di accedere al tuo database PostgreSQL, puoi connetterti direttamente a PgBouncer per gestirlo o monitorarlo. Per questo, usa lo stesso comando che hai usato in precedenza, ma cambia il database in "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
Ora puoi eseguire diversi comandi PgBouncer per monitorarlo:
MOSTRA 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)
MOSTRA SERVER:
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)
MOSTRA CLIENTI:
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)
MOSTRA PISCINE:
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 per gestirlo...
RICARICA:
pgbouncer=# RELOAD;
RELOAD
PAUSA:
pgbouncer=# PAUSE world;
PAUSE
RIPRENDI:
pgbouncer=# RESUME world;
RESUME
Questi comandi sono solo un esempio. Per un elenco completo dei comandi, fare riferimento alla documentazione ufficiale.
Conclusione
L'uso di una combinazione di PgBouncer + HAProxy + PostgreSQL è un buon modo per ottenere un'elevata disponibilità per il tuo cluster PostgreSQL migliorando allo stesso tempo le prestazioni del tuo database.
Come puoi vedere, se disponi del tuo ambiente PostgreSQL, che puoi distribuire utilizzando ClusterControl in pochi clic, puoi facilmente aggiungere PgBouncer per trarre vantaggio dall'avere un pool di connessioni per i tuoi sistemi.