# Pool di connessioni: tempi reali

Riusare la connessione costa 0,191 ms contro 0,598 ms su loopback: il pool paga il suo prezzo quando la rete ha latenza, non prima.

> Pagina: https://ui.eneawork.it/blog/pool-connessioni-tempi
> Markdown: https://ui.eneawork.it/blog/pool-connessioni-tempi.md

*2026-11-01*

Un pool di connessioni serve a non pagare l'apertura della connessione a ogni richiesta. Misurato su loopback con 200 richieste sequenziali, una connessione nuova costa 0,598 ms e una riusata da un pool keep-alive 0,191 ms: il triplo, senza che il server faccia nulla di diverso.

Server HTTP Node 24.15.0 in ascolto su 127.0.0.1, 1 novembre 2026: 200 richieste sequenziali con keepAlive: false hanno una media di 0,598 ms e un p95 di 0,996 ms; con un agent keepAlive: true e maxSockets: 10 la media è 0,191 ms e il p95 0,297 ms. Il burst di 200 richieste con concorrenza 5 passa da 108,2 ms a 26,6 ms, e il solo handshake TCP misurato su 200 connessioni costa 0,305 ms. Il catalogo EneUI conta 111.985 componenti, 1.556 blocchi e 12.808 icone da 1.472 librerie, letti da /api/stats lo stesso giorno.

## Cosa costa aprire una connessione

Aprire una connessione significa almeno tre passaggi: il handshake TCP, l'autenticazione e l'inizializzazione della sessione. PostgreSQL aggiunge un processo per ogni connessione, quindi il costo non è solo di rete ma anche di memoria e di scheduler. La documentazione di PostgreSQL 18, letta il 1 novembre 2026, ricorda che max_connections vale di norma 100 e che aumentarlo alza l'allocazione di memoria condivisa: il pool non è un optional, è il modo di stare sotto quel numero.

## I numeri, e cosa significano

Il risparmio misurato è di 0,407 ms per richiesta su loopback, dove la rete non aggiunge latenza. Su una connessione a 20 ms di andata e ritorno lo stesso handshake costa almeno tre volte la latenza, quindi il divario cresce di un ordine di grandezza. Il burst lo mostra in modo netto: 26,6 ms contro 108,2 ms, cioè quattro volte meno tempo per lo stesso lavoro.

## Quante connessioni tenere aperte

Parti dal numero di core disponibili per il database e moltiplica per le istanze dell'applicazione: il totale deve stare sotto max_connections meno le connessioni riservate ai superutenti, che sono tre per impostazione predefinita. Un pool da 20 connessioni su cinque istanze sono già cento connessioni, il limite di un PostgreSQL lasciato ai valori predefiniti. Il comando sotto mostra il tetto e l'uso reale.

psql "$DATABASE_URL" -Atc "show max_connections; show superuser_reserved_connections;" psql "$DATABASE_URL" -Atc "select state, count(*) from pg_stat_activity group by state order by 2 desc;"

## Il pool non è una coda infinita

Quando tutte le connessioni sono occupate, le richieste aspettano. Senza un timeout di acquisizione l'attesa cresce fino a superare il timeout del client, e il servizio sembra lento invece di sembrare saturo. Imposta un tempo massimo di attesa più corto del timeout dell'endpoint, un timeout sulle istruzioni e una metrica sulle attese: la latenza del pool va vista prima che diventi un incidente.

## Il limite: loopback non ha latenza

Questa misura è il pavimento, non il tetto. Su loopback la latenza di andata e ritorno è quasi zero, quindi il pool guadagna poco; su una rete reale guadagna molto di più, ma nessun pool accorcia una query lenta. Se una query impiega due secondi, la connessione resta occupata due secondi: il pool distribuisce l'attesa, non la elimina. In un ambiente serverless il problema cambia forma, perché ogni istanza apre le proprie connessioni e il pool va spostato sul database.

## Da dove partire

Calcola il tetto prima di scegliere la dimensione: istanze per connessioni per processo sotto max_connections.,Metti un timeout di acquisizione più corto del timeout dell'endpoint e monitora le attese.,Non mettere una chiamata lenta dentro una transazione: il pool resta occupato, come spiegato in transazioni ACID.,Difendi il tetto anche lato API con un rate limit che rifiuta prima di saturare il pool.,Per la parte visibile, la vista tabella, i blocchi dashboard e le card mostrano latenza e stato senza costruire un pannello da zero.,Se stai decidendo fra servizio gestito e self-hosted, il confronto è in Vercel e self-hosted; le regole dell'endpoint sono in progettare un'API.

## FAQ

### Quante connessioni deve avere un pool?

Poche, e legate ai core del database. Un valore di partenza è il numero di core, moltiplicato per le istanze dell'applicazione; il totale deve stare sotto max_connections meno le connessioni riservate.

### Meglio PgBouncer o il pool dell'applicazione?

Servono a cose diverse. Il pool dell'applicazione riduce le aperture per processo, PgBouncer condivide le connessioni fra più processi e istanze. Con molte istanze brevi, come in serverless, PgBouncer o un pooler gestito diventano necessari.

### Perché il pool non rende più veloci le query?

Perché elimina solo il costo di apertura. Il tempo di esecuzione dipende dal piano, dagli indici e dai dati; un pool pieno di query lente resta pieno, e l'attesa si sposta sulla coda.

### Cosa succede quando il pool è pieno?

Le richieste aspettano una connessione libera. Senza un timeout di acquisizione l'attesa supera il timeout del client e il servizio sembra guasto; con un timeout corto ricevi un errore rapido che puoi misurare.

### Serve un pool anche con SQLite?

No nel senso di PostgreSQL. SQLite apre il file, non un processo per client, e in modalità WAL permette lettori concorrenti con un solo scrittore. Il limite da gestire è la coda di scrittura, non il numero di connessioni.
