---
term: 'Connection pooling serverless nei database gestiti'
seoTitle: 'Connection pooling serverless nei database gestiti'
headline: 'Che cos''è il connection pooling serverless?'
slug: connection-pooling-serverless
category: database
shortDefinition: 'Il connection pooling serverless è una tecnica che condivide poche connessioni reali al database tra molte istanze di funzioni di breve durata.'
relatedTerms:
  - multi-tenant-database-architecture
  - serverless-architecture
  - auto-generated-database-apis
  - database-index
contrastsWith:
  - serverless-architecture
faq:
  - question: 'Perché il serverless esaurisce le connessioni al database?'
    answer: 'Perché due modelli di scalabilità entrano in collisione: il calcolo serverless moltiplica le istanze a ogni richiesta, mentre un database dispone di un budget di connessioni fisso – spesso intorno a 100 per impostazione predefinita. Ogni istanza di funzione apre la propria connessione, la tiene durante i tempi morti, e un picco di traffico che genera 500 istanze chiede 500 connessioni in una volta sola. Il database rifiuta l''eccedenza, e query che non c''entrano nulla iniziano a fallire.'
  - question: 'Che cosa fa davvero un pooler di connessioni come PgBouncer?'
    answer: 'Si colloca tra il codice e il database, accetta migliaia di connessioni client economiche e le multiplexa su un piccolo pool di connessioni server reali. I client credono di detenere una connessione; in realtà ne prendono una in prestito per una transazione o una sessione e poi la restituiscono. Il database vede un insieme di connessioni calmo e fisso, a prescindere da quante funzioni si avviano.'
  - question: 'Qual è la differenza tra pooling per transazione e pooling per sessione?'
    answer: 'La durata del prestito. Il pooling per sessione assegna una connessione reale per l''intera sessione del client – sicuro per ogni funzionalità, ma un client inattivo parcheggia comunque una connessione. Il pooling per transazione presta la connessione solo mentre una transazione è in corso, poi la recupera: la condivisione si moltiplica enormemente, ma lo stato di sessione si rompe – prepared statement, variabili di sessione e LISTEN/NOTIFY richiedono attenzione, altrimenti falliscono.'
  - question: 'Perché le connessioni schizzano quando le funzioni scalano?'
    answer: 'Una piattaforma serverless gestisce la concorrenza clonando le istanze, e ogni clone inizializza il proprio client del database. Il riuso delle connessioni avviene solo dentro una singola istanza calda, mai tra istanze diverse. Una concorrenza di 300 significa quindi 300 pool di dimensione uno – la forma peggiore possibile: tutto il sovraccarico del pooling senza alcuna condivisione. Il fan-out è strutturale, non un bug nel codice.'
  - question: 'Quanto dovrebbe essere grande un pool di connessioni al database?'
    answer: 'Molto più piccolo di quanto suggerisca l''intuizione. Il throughput di solito raggiunge il massimo con un pool vicino al parallelismo reale del database – una regola empirica comune è il numero di core per due, corretto per le attese su disco – non nelle centinaia. Oltre quel punto, le connessioni in più aggiungono contesa e costo in memoria senza aggiungere throughput. Il mestiere del pooler è proprio far sembrare infinito un pool piccolo a chi lo chiama.'
  - question: 'Serve ancora un pooler usando un BaaS?'
    answer: 'Non per il proprio traffico – è proprio questo il punto. Un backend gestito termina le richieste dei client come chiamate HTTPS stateless nel livello API; il suo livello server mantiene verso il database pool di lunga durata e dimensionati correttamente. Funzioni e app non detengono mai connessioni al database, quindi lo scenario di esaurimento sparisce invece di essere mitigato. I pooler tornano in gioco solo collegando direttamente strumenti esterni.'
  - question: 'Quali sono gli svantaggi dei pooler di connessioni?'
    answer: 'Aggiungono un salto di rete e quindi latenza, diventano un componente da far girare e monitorare, e la modalità transazione cambia la semantica in silenzio – le funzionalità legate alla sessione smettono di comportarsi come documentato. Un singolo processo pooler può diventare a sua volta il collo di bottiglia sotto un carico a picchi, e dimensionarlo male sposta soltanto la coda. È infrastruttura essenziale, ma è infrastruttura.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'PgBouncer features — pooling modes'
    url: 'https://www.pgbouncer.org/features.html'
  - name: 'PostgreSQL connection settings (max_connections)'
    url: 'https://www.postgresql.org/docs/current/runtime-config-connection.html'
  - name: 'Connection pool (Wikipedia)'
    url: 'https://en.wikipedia.org/wiki/Connection_pool'
  - name: 'Serverless Architectures — Mike Roberts (martinfowler.com)'
    url: 'https://martinfowler.com/articles/serverless.html'
cta:
  title: 'Salta del tutto il calcolo delle connessioni'
  text: 'Su Back4app i tuoi client e le funzioni Cloud Code parlano HTTPS stateless con API generate automaticamente, mentre la piattaforma mantiene pool dimensionati correttamente verso il database gestito – nessun pooler da distribuire, nessun max_connections da regolare, nessun incidente di esaurimento alle 3 di notte.'
  linkText: 'Inizia gratis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-10-23'
translationKey: serverless-connection-pooling
---

**Il connection pooling serverless è una tecnica che condivide poche connessioni reali al database tra molte istanze di funzioni di breve durata.** Esiste perché due modelli di scalabilità non vanno d'accordo: il [calcolo serverless](/glossary/it/architettura-serverless/) risponde al carico moltiplicando le istanze, mentre un database tratta ogni connessione come una risorsa costosa, sostenuta da memoria e con un tetto rigido. Messi insieme in modo ingenuo, un picco di traffico modesto diventa un'interruzione `too many connections`.

## Punti chiave

| Domanda | Risposta |
| --- | --- |
| La collisione | Le funzioni scalano per clonazione; le connessioni sono limitate e costose |
| Il sintomo | `FATAL: sorry, too many clients already` durante i picchi |
| La soluzione | Un pooler multiplexa molti client su poche connessioni reali |
| La manopola | Pooling per transazione vs. per sessione – condivisione vs. compatibilità |
| La risposta BaaS | I client parlano HTTPS stateless; la piattaforma possiede il pool |

## Il guasto, osservato dal database

```sql
-- Che cosa vede il database durante un picco di traffico serverless:
SELECT state, count(*)
FROM pg_stat_activity
GROUP BY state;
--  active               |   14
--  idle                 |  483     ← parcheggiate dalle istanze di funzione calde
SHOW max_connections;    --  100    ← il tetto che hanno già sfondato

-- Ogni connessione è un processo reale che occupa memoria reale –
-- ecco perché il tetto esiste e perché alzarlo non è la soluzione.
```

La forma del problema: ogni istanza di funzione apre la propria connessione, la tiene durante i tempi morti tra un'invocazione e l'altra, e il numero di istanze lo decide il traffico, non chi sviluppa. Il riuso avviene solo *dentro* un'istanza calda – mai tra istanze diverse – quindi una concorrenza di 300 significa 300 pool a connessione singola. Alzare [`max_connections`](https://www.postgresql.org/docs/current/runtime-config-connection.html) compra margine al prezzo di memoria reale e perde contro il picco successivo, più grande.

Su un backend gestito, il codice applicativo esce del tutto da questa lotta – le chiamate SDK sono richieste HTTPS stateless, e nessun client detiene mai una connessione al database:

**JavaScript:**

```javascript
// JavaScript / Node.js — Back4app JS SDK
// Inside a serverless function: no driver, no pool, no connection to leak.
// Each SDK call is a stateless HTTPS request; pooling happens platform-side.
Parse.initialize('APP_ID', 'JS_KEY');
Parse.serverURL = 'https://parseapi.back4app.com';

export async function handler(event) {
  const query = new Parse.Query('Order');
  query.equalTo('status', 'pending');
  query.limit(20);
  const orders = await query.find();  // request returns; nothing stays open
  return orders.map((o) => o.id);
}
// 1,000 concurrent invocations = 1,000 HTTP requests,
// not 1,000 database connections.
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// No driver, no pool, no connection to leak from the client side.
// Each SDK call is a stateless HTTPS request; pooling happens platform-side.
await Parse().initialize(
  'APP_ID',
  'https://parseapi.back4app.com',
  clientKey: 'CLIENT_KEY',
);

Future<List<String>> pendingOrderIds() async {
  final query = QueryBuilder<ParseObject>(ParseObject('Order'))
    ..whereEqualTo('status', 'pending')
    ..setLimit(20);
  final response = await query.query(); // request returns; nothing stays open
  return response.results!
      .map((o) => (o as ParseObject).objectId!)
      .toList();
}
// A burst of clients = a burst of HTTP requests,
// not a burst of database connections.
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// No driver, no pool, no connection to leak from the client side.
// Each SDK call is a stateless HTTPS request; pooling happens platform-side.
ParseSwift.initialize(
  applicationId: "APP_ID",
  clientKey: "CLIENT_KEY",
  serverURL: URL(string: "https://parseapi.back4app.com")!
)

let query = Order.query("status" == "pending")
  .limit(20)
query.find { result in
  if case .success(let orders) = result {
    render(orders)                 // request returned; nothing stays open
  }
}
// A burst of clients = a burst of HTTP requests,
// not a burst of database connections.
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// No driver, no pool, no connection to leak from the client side.
// Each SDK call is a stateless HTTPS request; pooling happens platform-side.
Parse.initialize(
    Parse.Configuration.Builder(context)
        .applicationId("APP_ID")
        .clientKey("CLIENT_KEY")
        .server("https://parseapi.back4app.com")
        .build()
)

val query = ParseQuery.getQuery<ParseObject>("Order")
query.whereEqualTo("status", "pending")
query.limit = 20
query.findInBackground { orders, e ->
    if (e == null) render(orders)  // request returned; nothing stays open
}
// A burst of clients = a burst of HTTP requests,
// not a burst of database connections.
```

## Come un pooler assorbe il fan-out

```mermaid
flowchart LR
  accTitle: Pooler di connessioni tra le funzioni serverless e il database
  accDescr: Centinaia di istanze di funzioni di breve durata aprono connessioni client economiche verso un pooler, che le multiplexa su un piccolo insieme fisso di connessioni reali al database, mantenendo il database sotto il suo limite di connessioni.
  F1["Funzione ×500<br/>(picco)"] --> P["Pooler<br/>(es. PgBouncer)"]
  F2["Funzione ×500<br/>(picco successivo)"] --> P
  P -->|"20 connessioni reali"| DB[("Database<br/>max_connections: 100")]
  P -. "i client attendono un istante in coda<br/>invece di fallire" .-> F1
```

Un pooler come [PgBouncer](https://www.pgbouncer.org/features.html) accetta connessioni client a migliaia – ciascuna economica dal suo lato – e presta connessioni server reali da un piccolo pool solo quando arriva del lavoro. Il database vede venti connessioni tranquille; cinquecento funzioni credono di averne una ciascuna. Quando la domanda supera il pool, i client attendono millisecondi in coda invece di ricevere errori – un fallimento secco si converte in una latenza modesta.

Il dimensionamento del pool è il punto in cui l'intuizione fallisce di più. Il parallelismo utile di un database è limitato da core e disco – il throughput di solito raggiunge il picco con un pool di poche decine di connessioni, intorno al numero di core per due, e poi *cala* man mano che altre connessioni aggiungono contesa. L'aritmetica del pooler funziona perché le richieste serverless sono brevi: una connessione che serve una transazione da 8 ms può servirne ben più di cento al secondo, quindi venti connessioni reali assorbono comodamente migliaia di invocazioni di funzioni. Il [pool](https://en.wikipedia.org/wiki/Connection_pool) non è una cache di comodo; è un collo di bottiglia deliberato, piazzato dove mettersi in coda costa poco.

La manopola cruciale è *quanto dura il prestito*.

## Pooling per transazione vs. pooling per sessione

| Dimensione | Pooling per sessione | Pooling per transazione |
| --- | --- | --- |
| Durata del prestito | L'intera sessione del client | Una transazione, poi la connessione viene recuperata |
| Moltiplicatore di condivisione | Basso – i client inattivi parcheggiano connessioni | Alto – ideale per il lavoro serverless breve |
| Prepared statement | Pienamente supportati | Solo tramite supporto a livello di protocollo, configurato esplicitamente |
| Stato di sessione (`SET`, tabelle temporanee, LISTEN/NOTIFY) | Funziona | Si rompe – transazioni diverse possono finire su connessioni diverse |
| Ideale per | App di lunga durata, strumenti di amministrazione, migrazioni | Traffico richiesta/risposta web e serverless |

La modalità transazione è ciò che rende praticabili i carichi serverless – una funzione che esegue una transazione da 8 ms non dovrebbe possedere una connessione per i minuti della sua vita a caldo – ma non è gratis: tutto ciò che presume che "la propria connessione" persista tra un'istruzione e l'altra diventa un bug subdolo. Il consiglio consolidato: pooling per transazione per il traffico di richieste, connessione diretta o con pool di sessione per le migrazioni e per tutto ciò che ha stato.

## Casi d'uso tipici

- **Funzioni serverless ed edge che interrogano SQL.** Il caso canonico – numeri di istanze a picchi contro un budget di connessioni fisso.
- **Molti piccoli servizi, un solo database.** Venti servizi × pool predefiniti da dieci connessioni = 200 connessioni che nessuno aveva pianificato; un pooler condiviso ristabilisce un'aritmetica sana.
- **[Piattaforme multi-tenant](/glossary/it/architettura-database-multi-tenant/).** I carichi per tenant moltiplicano la domanda di connessioni; il pooling permette di far rispettare il budget del database condiviso.
- **Raffiche di traffico su database modesti.** I picchi del giorno del lancio si mettono in coda al pooler per millisecondi invece di generare errori nel database.
- **Proteggere il primario durante gli incidenti.** Un pool di dimensione fissa è una paratia: i client fuori controllo esauriscono la coda del pooler, non la memoria del database.

## Conviene gestire un pooler in proprio? Matrice decisionale

| Gestire un pooler quando… | Lasciar perdere quando… |
| --- | --- |
| Funzioni o molti servizi si collegano direttamente a SQL | Un BaaS gestito termina il traffico dei client nel proprio livello API |
| Compaiono errori di connessione sotto i picchi di carico | Il traffico è costante e arriva da pochi server di lunga durata con pool lato client |
| Il database e il suo budget sono gestiti in proprio | La piattaforma fa già pooling tra il livello API e il database |
| Tenant o team condividono un unico database | Il carico è una sola app, un solo pool, ben dentro i limiti |
| C'è capacità operativa per un componente critico in più | Nessuno è in reperibilità per il pooler |

L'asimmetria, detta onestamente: un pooler risolve l'esaurimento delle connessioni; un backend gestito lo *dissolve*. Quando i client parlano HTTPS con [API generate automaticamente](/glossary/it/api-generate-automaticamente/), il fan-out non raggiunge mai il livello database – il pooling avviene comunque, ma come infrastruttura collaudata di qualcun altro anziché come componente da gestire in proprio.

## Limiti e trade-off

- **Un pooler è un componente.** Richiede deployment, monitoring, failover e aggiornamenti – si è scambiato un problema di risorse con un problema operativo, a un cambio favorevole ma non nullo.
- **La modalità transazione cambia la semantica.** Prepared statement, variabili di sessione e advisory lock smettono di comportarsi come documentato; i fallimenti sono intermittenti e dipendono dal carico – il tipo peggiore.
- **Un salto in più costa latenza.** Di norma sotto il millisecondo dentro la rete, ma sta sul percorso di ogni query.
- **Il pooler può essere il collo di bottiglia.** Un pooler a thread singolo sotto un picco violento accumula una coda profonda; il tetto si è spostato, non è sparito.
- **Il pooling non corregge le query lente.** Raziona le connessioni; una query che tiene il prestito per secondi lascia il pool a secco. Query veloci – e gli [indici](/glossary/it/indice-del-database/) dietro di esse – restano la vera leva di capacità.

## Il connection pooling su Back4app

Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. La sua architettura risponde alla domanda sul pooling in modo strutturale: le app client e le funzioni Cloud Code emettono richieste HTTPS stateless, ed è il livello server della piattaforma – non il codice applicativo – a mantenere pool di connessioni di lunga durata e dimensionati correttamente verso il database gestito. Il fan-out delle istanze sul lato di calcolo non si traduce mai in fan-out di connessioni sul lato database, che è esattamente la proprietà che tutto questo articolo esiste per costruire.
