Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Der Treiber go-mssqldb verwendet den integrierten Verbindungspool, der vom Go-Paket database/sql bereitgestellt wird. Jede Instanz sql.DB unterhält einen Pool von ungenutzten Verbindungen, die automatisch wiederverwendet werden. Dieser Artikel erklärt, wie Sie den Pool für Ihre Arbeitsbelastung konfigurieren können.
Wie das Schwimmbecken funktioniert
Wenn Sie db.QueryContext, db.ExecContext oder eine andere Datenbankmethode aufrufen:
- Der Pool versucht, eine Leerlaufverbindung zu finden.
- Wenn keine Leerlaufverbindung verfügbar ist und der Pool seine maximale Größe noch nicht erreicht hat, wird eine neue Verbindung erstellt.
- Wenn der Pool auf maximaler Kapazität ist, blockiert der Anruf, bis eine Verbindung verfügbar ist.
- Nach Abschluss der Operation wird die Verbindung zum Pool zurückgegeben.
Methoden der Poolkonfiguration
Konfigurieren Sie den Pool mit Methoden auf *sql.DB:
| Methode | Description |
|---|---|
db.SetMaxOpenConns(n) |
Maximale Anzahl offener Verbindungen (im Einsatz + Leerlauf). Standard: 0 (unbegrenzt). |
db.SetMaxIdleConns(n) |
Maximale Anzahl der ungenutzten Verbindungen im Pool. Standardwert: 2. |
db.SetConnMaxLifetime(d) |
Die maximale Gesamtzeit einer Verbindung kann wiederverwendet werden. Standard: 0 (keine Begrenzung). |
db.SetConnMaxIdleTime(d) |
Die maximale Zeit, in der eine Verbindung untätig bleiben kann, bevor sie geschlossen wird. Standard: 0 (keine Begrenzung). |
Example
Konfigurieren Sie den Pool unmittelbar nach dem Öffnen der Datenbank:
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)
Betrachte diese Werte als Ausgangspunkt, nicht als universellen Standard. Für viele Dienste ist der erste sinnvolle Schritt, MaxOpenConns und MaxIdleConns zu begrenzen und Lebensdauer- und Leerlauflimits erst dann hinzuzufügen, wenn Ihr Bereitstellungspfad zu veralteten oder ungleich verteilten Verbindungen führen kann.
Empfohlene Einstellungen
| Szenario | MaxOpen | MaxIdle | MaxLifetime | MaxIdleTime |
|---|---|---|---|---|
| Webanwendung auf einem stabilen SQL Server-Netzwerkpfad | 25 | 10 | 0 | 0 |
| Webanwendung über Azure SQL, ein Gateway oder einen Load Balancer | 25 | 10 | 5 Minuten | 1 Minute |
| Dienst mit hohem Durchsatz | 50-100 | 25 | 5 Minuten | 30 Sekunden |
| Hintergrundjob / CLI-Tool | 5 | 2 | 0 | 0 |
| Azure SQL-Datenbank (Basic/Standard) | 10 - 20 | 5 | 5 Minuten | 1 Minute |
Tip
Setzen Sie MaxOpenConns unter das Verbindungslimit Ihrer SQL Server-Instanz oder Azure SQL-Dienstebene. Das Überschreiten der maximalen gleichzeitigen Verbindungen des Servers führt zu Anmeldefehlern für alle Clienten.
Kurze ConnMaxLifetime- und ConnMaxIdleTime-Werte verringern die Wahrscheinlichkeit veralteter Verbindungen nach einem Failover oder Gateway-Recycling, erhöhen aber auch das häufige Neuaufbauen und Trennen von Verbindungen. Wenn deine App direkt eine Verbindung mit einer stabilen SQL Server-Instanz herstellt und keine Fehler aufgrund veralteter Verbindungen auftreten, ist es sinnvoll, beide Werte auf 0 zu belassen.
Pool-Statistiken überwachen
Verwenden Sie db.Stats(), um aktuelle Pool-Statistiken abzurufen:
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)
Schlüsselfelder:
| Feld | Description |
|---|---|
OpenConnections |
Total offene Verbindungen (im Gebrauch + Leerlauf). |
InUse |
Die Verbindungen werden derzeit von Anrufern überprüft. |
Idle |
Im Pool wartende Verbindungen. |
WaitCount |
Die Gesamtzahl der Male, in denen ein Anrufer auf eine Verbindung warten musste. |
WaitDuration |
Gesamtkumulierte Wartezeit. |
Wenn WaitCount stetig wächst, erhöhen Sie MaxOpenConns nicht automatisch. Überprüfen Sie zunächst, ob Zeilen, Transaktionen und dedizierte Verbindungen umgehend geschlossen werden, und bestätigen Sie, dass der Server einen größeren Pool unterstützen kann.
SessionInitSQL
Verwenden Sie SessionInitSQL, um bei jeder neuen Verbindung eine SQL-Anweisung auszuführen, wenn sie in den Pool aufgenommen wird. Diese Funktion ist nützlich, um Optionen auf Sitzungsebene einzustellen:
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)
Verbindungs-Pinning
Bestimmte Operationen binden eine Verbindung, sodass sie erst dann in den Pool zurückgegeben wird, wenn die Operation abgeschlossen ist:
-
Transaktionen (
db.BeginTx) - Die Verbindung bleibt gebunden, bisCommit()oderRollback()aufgerufen wird. -
Einzelverbindungen (
db.Conn) – Die Verbindung bleibt gepinnt, bisconn.Close()aufgerufen wird. -
Offene Zeilen (
db.QueryContext) – Die Verbindung bleibt gepinnt, bisrows.Close()aufgerufen wird.
Schließe diese Ressourcen immer umgehend, um den Pool nicht zu verhungern.
Pool-Erschöpfung erkennen und auflösen
Eine Pool-Erschöpfung tritt auf, wenn alle Verbindungen belegt sind und der Pool MaxOpenConns erreicht hat. Neue Anrufer blockieren, bis eine Verbindung zurückgerufen wird. Zu den Symptomen gehören eine hohe Latenz, eine Anhäufung von Goroutinen und schließlich Fehler aufgrund überschrittener Kontext-Deadlines.
Auf Erschöpfung überwachen
db.Stats() regelmäßig abfragen und bei Erkennung eines Konflikts warnen:
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)
}
}
}
}
Häufige Ursachen und Lösungen
| Ursache | Symptom | Lösung |
|---|---|---|
MaxOpenConns Zu gering für die Arbeitsbelastung |
WaitCount wächst stetig. |
Erhöhe MaxOpenConns. |
| Zeilen, die in Fehlerpfaden nicht abgeschlossen sind |
InUse wächst, Idle bleibt bei 0. |
Verwenden defer rows.Close() Sie sofort nach QueryContext. |
| Lang andauernde Transaktionen |
InUse bleibt weiterhin hoch. |
Halten Sie die Transaktionen kurz. Nutze Kontext-Timeouts. |
db.Conn unnötig verwendet |
InUse höher als erwartet. |
Verwende db.Conn nur, wenn du einen sitzungsbezogenen Status (temporäre Tabellen) benötigst. |
MaxOpenConns nicht festgelegt (unbegrenzt) |
Hunderte offene Verbindungen unter Last. | Setzen Sie MaxOpenConns immer auf einen begrenzten Wert. |
Gesundheitsprüfungen und Erkennung von veralteten Verbindungen
Der Pool validiert inaktive Verbindungen nicht aktiv. Eine Verbindung, die untätig blieb, während der Server sie recycelte, schlägt bei der nächsten Nutzung fehl. Konfigurieren Sie ConnMaxLifetime und ConnMaxIdleTime so, dass Verbindungen rotiert werden, bevor sie inaktiv werden:
// 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)
Hinweis
Wenn ConnMaxIdleTime inaktive Verbindungen proaktiv schließt, zeigen die SQL Server-Protokolle möglicherweise an, dass Verbindungen getrennt werden. Das ist erwartetes Verhalten, kein Verbindungsleck. Wenn Ihr DBA unerwartete Verbindungsschließungen meldet, überprüfen Sie, ob die Einstellung ConnMaxIdleTime mit den Überwachungserwartungen des Teams übereinstimmt.
Wenn Ihre Anwendung über einen Load Balancer oder Azure SQL mit Geo-Replikation eine Verbindung herstellt, setzen Sie ConnMaxLifetime auf 5 Minuten oder weniger. Diese Einstellung stellt sicher, dass Verbindungen nach einem Failover über Replikate verteilt werden.
Validiere die Konnektivität beim Start
Immer nach dem Öffnen der Datenbank aufrufendb.PingContext, um zu bestätigen, dass die Verbindungszeichenfolge korrekt ist und der Server erreichbar ist:
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)
}
Exportpool-Metriken
Machen Sie Pool-Statistiken für Ihr Überwachungssystem verfügbar, indem Sie db.Stats() regelmäßig auslesen:
Beispiel Prometheus
Registriere Messgeräte, die Pool-Statistiken verfolgen, und aktualisieren sie regelmäßig:
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
}
}
}
Poolkonfigurations-Checkliste
| Area | Recommendation |
|---|---|
MaxOpenConns |
Immer auf einen beschränkten Wert gesetzt. Passen Sie es an die Parallelität Ihrer Workloads an, unter dem Verbindungslimit des Servers. |
MaxIdleConns |
Auf mindestens die Hälfte von MaxOpenConns setzen. Zu wenige Leerlaufverbindungen verursachen häufigen Wiederanschluss-Overhead. |
ConnMaxLifetime |
Legen Sie für Azure SQL oder lastenausgeglichene Umgebungen 5 Minuten fest. Verhindert die Ansammlung veralteter Verbindungen. |
ConnMaxIdleTime |
Stellen Sie auf 30-60 Sekunden, um Verbindungen zu schließen, die nicht mehr benötigt werden. |
| Monitoring | Umfrage db.Stats() und Warnung zum WaitCount Wachstum. |
| Ressourcenbereinigung | Immer defer rows.Close(), defer tx.Rollback(), und defer conn.Close(). |
| Startbestätigung | Rufen Sie db.PingContext nach sql.Open auf, um die Konnektivität zu überprüfen. |