Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Ovladač go-mssqldb využívá vestavěný pool připojení poskytovaný database/sql balíčkem Go. Každá sql.DB instance udržuje zásobník nečinných připojení, která jsou automaticky znovu použita. Tento článek vysvětluje, jak nastavit pool pro vaši pracovní zátěž.
Jak bazén funguje
Když voláte db.QueryContext, db.ExecContext, nebo jakoukoli jinou databázovou metodu:
- Bazén se snaží najít nečinné spojení.
- Pokud není k dispozici žádné nečinné připojení a pool nedosáhl maximální velikosti, vytvoří se nové připojení.
- Pokud je pool na maximální kapacitě, volání blokuje, dokud není k dispozici připojení.
- Po dokončení operace je spojení vráceno do poolu.
Metody konfigurace poolu
Nakonfigurujte pool pomocí metod na *sql.DB:
| Metoda | Description |
|---|---|
db.SetMaxOpenConns(n) |
Maximální počet otevřených připojení (používaných + nečinných). Výchozí: 0 (neomezené). |
db.SetMaxIdleConns(n) |
Maximální počet nečinných připojení v poolu. Výchozí hodnota: 2. |
db.SetConnMaxLifetime(d) |
Maximální celková doba, po kterou lze spojení znovu použít. Výchozí: 0 (bez limitu). |
db.SetConnMaxIdleTime(d) |
Maximální dobu, po kterou může spojení zůstat nečinné, než se uzavře. Výchozí: 0 (bez limitu). |
Example
Nakonfigurujte pool ihned po otevření databáze:
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)
Tyto hodnoty berte jako výchozí bod, ne jako univerzální výchozí hodnotu. U mnoha služeb je jako první užitečný krok nastavit limity pro MaxOpenConns a MaxIdleConns a limity životnosti a doby nečinnosti přidat pouze tehdy, když váš způsob nasazení může vést k zastaralým nebo nerovnoměrně rozloženým připojením.
Doporučená nastavení
| Scénář | MaxOpen | MaxIdle | MaxLifetime | MaxIdleTime |
|---|---|---|---|---|
| Webová aplikace ve stabilní síti SQL Serveru | 25 | 10 | 0 | 0 |
| Webová aplikace prostřednictvím Azure SQL, brány nebo load balanceru | 25 | 10 | 5 minut | 1 minuta |
| Služba s vysokou propustností | 50-100 | 25 | 5 minut | 30 sekund |
| Úloha na pozadí / nástroj CLI | 5 | 2 | 0 | 0 |
| Azure SQL Database (Basic/Standard) | 10–20 | 5 | 5 minut | 1 minuta |
Tip
Nastavte MaxOpenConns pod limit připojení vaší instance SQL Server nebo úrovně Azure SQL. Překročení maximálního souběžného připojení serveru způsobuje neúspěchy přihlášení u všech klientů.
Krátké hodnoty ConnMaxLifetime a ConnMaxIdleTime snižují pravděpodobnost neplatných připojení po failoveru nebo recyklaci brány, ale také zvyšují četnost vytváření a ukončování připojení. Pokud se vaše aplikace připojuje přímo ke stabilní instanci SQL Serveru a nedochází k selháním způsobeným neplatnými připojeními, je rozumné ponechat obě hodnoty na 0.
Sledujte statistiky poolu
Použijte db.Stats() pro čtení aktuálních statistik poolu:
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)
Klíčová pole:
| Obor | Description |
|---|---|
OpenConnections |
Úplné otevřené připojení (v provozu + nečinnost). |
InUse |
Spojení jsou aktuálně ověřena volajícími. |
Idle |
Spojení čekají v bazénu. |
WaitCount |
Celkový počet případů, kdy musel volající čekat na spojení. |
WaitDuration |
Celková kumulativní doba čekání. |
Pokud WaitCount roste stabilně, nezvyšujte MaxOpenConns to automaticky. Nejprve ověřte, že řádky, transakce a vyhrazená připojení jsou rychle uzavírány, a potvrďte, že server zvládne větší pool.
SessionInitSQL
Používám SessionInitSQL SQL příkaz při každém novém připojení, které vstupuje do poolu. Tato funkce je užitečná pro nastavení možností na úrovni relace:
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)
Připnutí spojů
Některé operace připnou spojení tak, aby se nevrátilo do poolu, dokud operace neskončí:
-
Transakce (
db.BeginTx) – Připojení je vyhrazeno, dokud není zavolánoCommit()neboRollback(). -
Jednorázová spojení (
db.Conn) - Spojení je připnuto, dokudconn.Close()není vyvoláno. -
Otevřené řádky (
db.QueryContext) - Spojení je připnuté, dokudrows.Close()není vyvoláno.
Vždy tyto zdroje rychle zavřete, abyste nepřišli o bazén.
Detekce a řešení vyčerpání bazénu
K vyčerpání fondu dochází, když jsou všechna připojení používána a fond dosáhl MaxOpenConns. Noví volající blokují, dokud není spojení vráceno. Příznaky zahrnují vysokou latenci, hromadění gorutiny a případné chyby kontextových termínů.
Monitor vyčerpání
Pravidelně dotazujte db.Stats() a upozorněte při zjištění kolize:
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)
}
}
}
}
Běžné příčiny a jejich řešení
| Příčina | Symptom | Solution |
|---|---|---|
MaxOpenConns příliš nízké pro dané zatížení |
WaitCount roste stabilně. |
Zvýšit MaxOpenConns. |
| Řádky nejsou uzavřené v chybových cestách |
InUse roste, Idle zůstává na nule. |
Použijte defer rows.Close() ihned po QueryContext. |
| Dlouhotrvající transakce |
InUse zůstává na vysoké úrovni. |
Udržujte transakce krátké. Používejte časové limity v kontextu. |
db.Conn Používáno zbytečně |
InUse Vyšší, než jsem čekal. |
Používejte db.Conn jen tehdy, když potřebujete stav zaměřený na relaci (dočasné tabulky). |
MaxOpenConns Nenastaveno (neomezené) |
Stovky otevřených připojení při zátěži. | Vždy nastaveno MaxOpenConns na omezenou hodnotu. |
Zdravotní kontroly a detekce zastaralého spojení
Pool aktivně nevaliduje nečinná připojení. Připojení, které zůstalo nečinné, zatímco ho server recykloval, selže při dalším použití. Konfigurujte a otáčejte ConnMaxLifetimeConnMaxIdleTime spojení dříve, než se stanou zastaranými:
// 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
Když ConnMaxIdleTime proaktivně uzavírá nečinná připojení, logy SQL Server mohou ukazovat ztrátu spojení. Jde o očekávané chování, nejde o únik připojení. Pokud váš DBA hlásí neočekávaná uzavření připojení, ověřte, že nastavení ConnMaxIdleTime odpovídá očekáváním týmu ohledně monitorování.
Pokud se vaše aplikace připojuje přes load balancer nebo Azure SQL s geo-replikací, nastavte ConnMaxLifetime na 5 minut nebo méně. Toto nastavení zajišťuje, že spojení jsou po failoveru přerozdělena mezi repliky.
Validujte konektivitu při spuštění
Vždy volejte db.PingContext po otevření databáze, abyste potvrdili, že připojovací řetězec je správný a server dostupný:
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)
}
Metriky exportního poolu
Zpřístupněte statistiky poolu svému monitorovacímu systému pravidelným čtením db.Stats():
Příklad Promethea
Zaregistrujte metriky, které sledují statistiky poolu, a pravidelně je aktualizujte:
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
}
}
}
Kontrolní seznam konfigurace bazénu
| Area | Recommendation |
|---|---|
MaxOpenConns |
Vždy nastaveno na omezenou hodnotu. Nastavte ji podle souběžnosti pracovní zátěže tak, aby zůstala pod limitem počtu připojení serveru. |
MaxIdleConns |
Nastavte alespoň na polovinu hodnoty MaxOpenConns. Příliš málo nečinných připojení způsobuje častou režii spojenou s opětovným navazováním připojení. |
ConnMaxLifetime |
Nastavte na 5 minut pro Azure SQL nebo prostředí s vyrovnáváním zátěže. Zabraňuje hromadění neaktivních spojení. |
ConnMaxIdleTime |
Nastavte na 30-60 sekund na uzavření spojení, která už nejsou potřeba. |
| Monitoring | Pravidelně kontrolujte db.Stats() a upozorněte na růst WaitCount. |
| Vyčištění prostředků | Vždy defer rows.Close(), defer tx.Rollback(), a defer conn.Close(). |
| Validace spuštění | Po sql.Open spusťte db.PingContext a ověřte připojení. |