Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Il go-mssqldb driver utilizza il pool di connessione integrato fornito dal pacchetto di database/sql Go. Ogni sql.DB istanza mantiene un pool di connessioni inattive che vengono riutilizzate automaticamente. Questo articolo spiega come configurare il pool per il tuo carico di lavoro.
Come funziona la piscina
Quando chiami db.QueryContext, db.ExecContext, o qualsiasi altro metodo di database:
- La piscina cerca di trovare una connessione inattiva.
- Se non è disponibile una connessione inattiva e il pool non ha raggiunto la sua dimensione massima, viene creata una nuova connessione.
- Se il pool è alla massima capacità, la chiamata si blocca finché non diventa disponibile una connessione.
- Dopo il completamento dell'operazione, la connessione viene restituita al pool.
Metodi di configurazione del pool
Configura il pool usando metodi su *sql.DB:
| metodo | Description |
|---|---|
db.SetMaxOpenConns(n) |
Numero massimo di connessioni aperte (in uso + inattività). Predefinito: 0 (illimitato). |
db.SetMaxIdleConns(n) |
Numero massimo di connessioni inattive nella piscina. Impostazione predefinita: 2. |
db.SetConnMaxLifetime(d) |
Tempo totale massimo di riutilizzo di una connessione. Predefinito: 0 (nessun limite). |
db.SetConnMaxIdleTime(d) |
Il tempo massimo in cui una connessione può rimanere inattiva prima di essere chiusa. Predefinito: 0 (nessun limite). |
Example
Configura il pool immediatamente dopo aver aperto il database:
db, err := sql.Open("sqlserver", connString)
if err != nil {
log.Fatal(err)
}
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(5 * time.Minute)
db.SetConnMaxIdleTime(1 * time.Minute)
Considera questi valori come un punto di partenza, non come un predefinito universale. Per molti servizi, il primo passo utile è impostare limiti limitati MaxOpenConns e MaxIdleConns, poi aggiungere limiti di durata e inattività solo quando il percorso di distribuzione può lasciarti con connessioni obsolete o distribuite in modo disomogeneo.
Impostazioni consigliate
| Scenario | MaxOpen | MaxIdle | MaxLifetime | MaxIdleTime |
|---|---|---|---|---|
| Applicazione web su un percorso stabile di rete SQL Server | 25 | 10 | 0 | 0 |
| Applicazione web tramite Azure SQL, un gateway o un bilanciatore di carico | 25 | 10 | 5 minuti | 1 minuto |
| Servizio ad alta produttività | 50-100 | 25 | 5 minuti | 30 secondi |
| Lavoro di background / Strumento CLI | 5 | 2 | 0 | 0 |
| database SQL di Azure (Basic/Standard) | 10-20 | 5 | 5 minuti | 1 minuto |
Tip
Imposta MaxOpenConns sotto il limite di connessione della tua istanza SQL Server o del tier Azure SQL. Superare il limite massimo di connessioni concorrenti del server causa fallimenti di accesso per tutti i client.
Valori brevi per ConnMaxLifetime e ConnMaxIdleTime riducono la probabilità di connessioni non più valide dopo il failover o il riciclo del gateway, ma aumentano anche il ricambio delle connessioni. Se la tua app si connette direttamente a un'istanza stabile di SQL Server e non riscontri errori dovuti a connessioni non più valide, è ragionevole lasciare entrambi i valori su 0.
Monitorare le statistiche del pool
Da usare db.Stats() per leggere le statistiche attuali del pool:
stats := db.Stats()
fmt.Printf("Open: %d, InUse: %d, Idle: %d\n",
stats.OpenConnections, stats.InUse, stats.Idle)
fmt.Printf("WaitCount: %d, WaitDuration: %v\n",
stats.WaitCount, stats.WaitDuration)
Campi chiave:
| Campo | Description |
|---|---|
OpenConnections |
Totale delle connessioni aperte (in uso + inattività). |
InUse |
Collegamenti attualmente controllati dai chiamanti. |
Idle |
Connessioni in attesa nel pool. |
WaitCount |
Numero totale di volte in cui un chiamante ha dovuto aspettare una connessione. |
WaitDuration |
Tempo totale cumulativo di attesa. |
Se WaitCount sta crescendo costantemente, non aumentare MaxOpenConns automaticamente. Prima verifica che righe, transazioni e connessioni dedicate vengano chiuse prontamente e conferma che il server possa supportare un pool più ampio.
SessionInitSQL
Usalo SessionInitSQL per eseguire un'istruzione SQL su ogni nuova connessione man mano che entra nel pool. Questa funzione è utile per impostare le opzioni a livello di sessione:
import (
"database/sql"
"github.com/microsoft/go-mssqldb"
"github.com/microsoft/go-mssqldb/msdsn"
)
config := msdsn.Config{
Host: "<server>",
Port: 1433,
Database: "AdventureWorks2025",
}
connector := mssql.NewConnectorConfig(config)
connector.SessionInitSQL = "SET ANSI_NULLS ON; SET QUOTED_IDENTIFIER ON"
db := sql.OpenDB(connector)
Blocco della connessione
Alcune operazioni vincolano una connessione in modo che non venga restituita al pool finché l'operazione non termina:
-
Transazioni (
db.BeginTx) - La connessione è vincolata finchéCommit()oRollback()non viene chiamata. -
Connessioni singole (
db.Conn) - La connessione rimane associata finchéconn.Close()non viene chiamato. -
Righe aperte (
db.QueryContext) - La connessione rimane bloccata finché non viene chiamatorows.Close().
Chiudi sempre tempestivamente queste risorse per evitare di esaurire il pool.
Rilevare e risolvere l'esaurimento del pool di risorse
L'esaurimento della piscina si verifica quando tutte le connessioni sono in uso e la piscina ha raggiunto MaxOpenConns. I nuovi chiamanti bloccano finché non viene restituita una connessione. I sintomi includono alta latenza, accumulo di goroutine e eventuali errori di scadenza contestuale.
Monitorare la stanchezza
Interroga db.Stats() periodicamente e avvisa quando viene rilevata una contesa:
func monitorPool(ctx context.Context, db *sql.DB, interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
var lastWaitCount int64
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
stats := db.Stats()
newWaits := stats.WaitCount - lastWaitCount
lastWaitCount = stats.WaitCount
if newWaits > 0 {
log.Printf("POOL CONTENTION: %d new waits, avg wait %v, open=%d, inUse=%d, idle=%d",
newWaits, stats.WaitDuration/time.Duration(stats.WaitCount),
stats.OpenConnections, stats.InUse, stats.Idle)
}
}
}
}
Cause comuni e soluzioni
| Cause | Sintomo | Soluzione |
|---|---|---|
MaxOpenConns troppo basso per il carico di lavoro |
WaitCount cresce costantemente. |
Aumentare MaxOpenConns. |
| Righe non chiuse nei percorsi di errore |
InUse cresce, Idle rimane a 0. |
Usa defer rows.Close() immediatamente dopo QueryContext. |
| Transazioni a esecuzione prolungata |
InUse rimane alto. |
Mantieni le transazioni brevi. Usa i timeout di contesto. |
db.Conn usata inutilmente |
InUse più alto del previsto. |
Usa db.Conn solo quando hai bisogno di uno stato limitato all'ambito della sessione (tabelle temporanee). |
MaxOpenConns non impostato (illimitato) |
Centinaia di connessioni aperte sotto carico. | Imposta MaxOpenConns sempre su un valore limitato. |
Controlli di salute e rilevamento delle connessioni obsolete
Il pool non convalida attivamente le connessioni inattive. Una connessione rimasta inattiva mentre il server la riciclava si guasta al prossimo utilizzo. Configurare ConnMaxLifetime e ConnMaxIdleTime per ruotare le connessioni prima che diventino obsolete:
// Rotate connections every 5 minutes to stay compatible
// with load balancers and Azure SQL failover.
db.SetConnMaxLifetime(5 * time.Minute)
// Close connections that have been idle for over 1 minute
// to reduce the number of stale connections.
db.SetConnMaxIdleTime(1 * time.Minute)
Note
Quando ConnMaxIdleTime chiude le connessioni inattive in modo proattivo, i log di SQL Server potrebbero mostrare la perdita delle connessioni. Questo è un comportamento previsto, non una perdita di connessione. Se il tuo DBA segnala chiusure di connessione impreviste, verifica che l'impostazione ConnMaxIdleTime sia in linea con le aspettative di monitoraggio del team.
Se la tua applicazione si collega tramite un bilanciatore di carico o Azure SQL con geo-replicazione, imposta ConnMaxLifetime a 5 minuti o meno. Questa impostazione garantisce che le connessioni vengano ridistribuite tra le repliche dopo un failover.
Valida la connettività all'avvio
Chiama db.PingContext sempre dopo aver aperto il database per confermare che la stringa di connessione è corretta e che il server è raggiungibile:
db, err := sql.Open("sqlserver", connString)
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := db.PingContext(ctx); err != nil {
log.Fatalf("Cannot connect to database: %v", err)
}
Metriche del pool di esportazione
Esponi le statistiche dei pool al tuo sistema di monitoraggio leggendo db.Stats()periodicamente:
Esempio di Prometheus
Registra gli indicatori che tracciano le statistiche del pool e aggiornali periodicamente:
import "github.com/prometheus/client_golang/prometheus"
var (
dbOpenConns = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "db_open_connections",
Help: "Number of open database connections.",
})
dbInUseConns = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "db_in_use_connections",
Help: "Number of connections currently in use.",
})
dbWaitCount = prometheus.NewCounter(prometheus.CounterOpts{
Name: "db_wait_count_total",
Help: "Total number of times a caller waited for a connection.",
})
dbWaitDuration = prometheus.NewCounter(prometheus.CounterOpts{
Name: "db_wait_duration_seconds_total",
Help: "Total wait time for a connection.",
})
)
func init() {
prometheus.MustRegister(dbOpenConns, dbInUseConns, dbWaitCount, dbWaitDuration)
}
func recordPoolMetrics(ctx context.Context, db *sql.DB) {
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
var lastWaitCount int64
var lastWaitDuration time.Duration
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
stats := db.Stats()
dbOpenConns.Set(float64(stats.OpenConnections))
dbInUseConns.Set(float64(stats.InUse))
dbWaitCount.Add(float64(stats.WaitCount - lastWaitCount))
dbWaitDuration.Add((stats.WaitDuration - lastWaitDuration).Seconds())
lastWaitCount = stats.WaitCount
lastWaitDuration = stats.WaitDuration
}
}
}
Elenco di controllo per la configurazione del pool
| Area | Raccomandazione |
|---|---|
MaxOpenConns |
Imposta sempre un valore delimitato. Impostalo in base al livello di concorrenza del tuo carico di lavoro, al di sotto del limite di connessioni del server. |
MaxIdleConns |
Impostato ad almeno metà di MaxOpenConns. Un numero troppo basso di connessioni inattive comporta frequenti sovraccarichi dovuti alla riconnessione. |
ConnMaxLifetime |
Impostare su 5 minuti per Azure SQL o per ambienti con bilanciamento del carico. Previene l'accumulo di connessioni stantie. |
ConnMaxIdleTime |
Imposta su 30-60 secondi per chiudere le connessioni che non sono più necessarie. |
| Monitoring | Sondaggi db.Stats() e avvisi sulla WaitCount crescita. |
| Pulizia delle risorse | Sempre defer rows.Close(), defer tx.Rollback(), e defer conn.Close(). |
| Validazione dell'avvio | Chiama db.PingContext dopo sql.Open per verificare la connettività. |