Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Driver go-mssqldb menggunakan kumpulan koneksi bawaan yang disediakan oleh paket Go database/sql . Setiap sql.DB instans mempertahankan kumpulan koneksi menganggur yang digunakan kembali secara otomatis. Artikel ini menjelaskan cara mengonfigurasi kumpulan untuk beban kerja Anda.
Cara kerja kolam renang
Saat Anda memanggil db.QueryContext, db.ExecContext, atau metode database lainnya:
- Kumpulan mencoba menemukan koneksi yang tidak aktif.
- Jika tidak ada koneksi menganggur yang tersedia dan kumpulan belum mencapai ukuran maksimumnya, koneksi baru akan dibuat.
- Jika kumpulan berada pada kapasitas maksimum, panggilan diblokir hingga koneksi tersedia.
- Setelah operasi selesai, koneksi dikembalikan ke pool.
Metode konfigurasi kumpulan
Konfigurasikan kumpulan menggunakan metode pada *sql.DB:
| Metode | Description |
|---|---|
db.SetMaxOpenConns(n) |
Jumlah maksimum koneksi terbuka (digunakan + tidak aktif). Default: 0 (tidak terbatas). |
db.SetMaxIdleConns(n) |
Jumlah maksimum koneksi yang tidak aktif dalam pool. Standar: 2. |
db.SetConnMaxLifetime(d) |
Total waktu maksimum koneksi dapat digunakan kembali. Default: 0 (tanpa batas). |
db.SetConnMaxIdleTime(d) |
Waktu maksimum koneksi dapat tetap tidak aktif sebelum ditutup. Default: 0 (tanpa batas). |
Example
Konfigurasikan kumpulan segera setelah membuka 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)
Perlakukan nilai-nilai ini sebagai titik awal, bukan default universal. Untuk banyak layanan, langkah pertama yang berguna adalah menetapkan batas terbatas MaxOpenConns dan MaxIdleConns, lalu menambahkan batas masa pakai dan idle hanya ketika jalur penyebaran Anda dapat membuat Anda memiliki koneksi kedaluwarsa atau tidak merata.
Pengaturan yang direkomendasikan
| Skenario | MaxOpen | MaxIdle | Masa Pakai Maks | MaxIdleTime |
|---|---|---|---|---|
| Aplikasi web pada jalur jaringan SQL Server yang stabil | 25 | 10 | 0 | 0 |
| Aplikasi web melalui Azure SQL, gateway, atau penyeimbang beban | 25 | 10 | 5 menit | 1 menit |
| Layanan dengan throughput tinggi | 50-100 | 25 | 5 menit | 30 detik |
| Pekerjaan latar belakang / alat CLI | 5 | 2 | 0 | 0 |
| Azure SQL Database (Dasar/Standar) | 10-20 | 5 | 5 menit | 1 menit |
Tip
Tetapkan MaxOpenConns di bawah batas koneksi instans SQL Server atau tingkat Azure SQL Anda. Melebihi koneksi bersamaan maksimum server menyebabkan kegagalan login untuk semua klien.
Nilai ConnMaxLifetime dan ConnMaxIdleTime yang pendek mengurangi kemungkinan koneksi usang setelah failover atau gateway dimulai ulang, tetapi juga meningkatkan frekuensi putus-sambung koneksi. Jika aplikasi Anda terhubung langsung ke instans SQL Server yang stabil dan Anda tidak mengalami kegagalan akibat koneksi usang, membiarkan kedua nilai tetap di 0 adalah hal yang wajar.
Memantau statistik kumpulan
Gunakan db.Stats() untuk membaca statistik kumpulan saat ini:
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)
Bidang kunci:
| Ladang | Description |
|---|---|
OpenConnections |
Total koneksi terbuka (sedang digunakan + menganggur). |
InUse |
Koneksi saat ini diperiksa oleh penelepon. |
Idle |
Koneksi menunggu di kolam renang. |
WaitCount |
Berapa kali penelepon harus menunggu koneksi. |
WaitDuration |
Total waktu tunggu kumulatif. |
Jika WaitCount terus bertambah secara stabil, jangan tingkatkan MaxOpenConns secara otomatis. Pertama, verifikasi bahwa baris data, transaksi, dan koneksi terdedikasi ditutup dengan segera, lalu pastikan bahwa server dapat mendukung pool yang lebih besar.
SessionInitSQL
Gunakan SessionInitSQL untuk menjalankan pernyataan SQL pada setiap koneksi baru saat memasuki kumpulan. Fitur ini berguna untuk mengatur opsi tingkat sesi:
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)
Penyematan koneksi
Operasi tertentu menyematkan koneksi sehingga tidak dikembalikan ke kumpulan hingga operasi berakhir:
-
Transaksi (
db.BeginTx) - Koneksi tetap terikat hinggaCommit()atauRollback()dipanggil. -
Koneksi tunggal (
db.Conn) - Koneksi tetap terikat hingga fungsiconn.Close()dipanggil. -
Baris yang terbuka (
db.QueryContext) - Koneksi tetap terikat hinggarows.Close()dipanggil.
Selalu tutup sumber daya ini segera untuk menghindari kelaparan kolam.
Mendeteksi dan mengatasi kelelahan kolam renang
Kelelahan kolam terjadi ketika semua koneksi sedang digunakan dan kolam telah mencapai MaxOpenConns. Penelepon baru memblokir hingga koneksi dikembalikan. Gejalanya termasuk latensi tinggi, penumpukan goroutine, dan kesalahan tenggat waktu konteks akhirnya.
Pantau kelelahan
Jajak pendapat db.Stats() secara berkala dan peringatkan saat perselisihan terdeteksi:
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)
}
}
}
}
Penyebab Umum dan Solusi
| Penyebab | Gejala | Solusi |
|---|---|---|
MaxOpenConns terlalu rendah untuk beban kerja |
WaitCount tumbuh dengan mantap. |
Tingkatkan MaxOpenConns. |
| Baris tidak ditutup pada jalur penanganan kesalahan |
InUse tumbuh, Idle tetap di 0. |
Gunakan defer rows.Close() segera setelah QueryContext. |
| Transaksi jangka panjang |
InUse tetap tinggi. |
Jaga agar transaksi tetap singkat. Gunakan batas waktu konteks. |
db.Conn digunakan secara tidak perlu |
InUse lebih tinggi dari yang diharapkan. |
Gunakan db.Conn hanya saat Anda memerlukan status lingkup sesi (tabel sementara). |
MaxOpenConns Tidak diatur (tidak terbatas) |
Ratusan koneksi terbuka saat sistem terbebani. | Selalu atur MaxOpenConns ke nilai terbatas. |
Pemeriksaan kesehatan dan deteksi koneksi kedaluwarsa
Pool tidak secara aktif memvalidasi koneksi idle. Koneksi yang menganggur saat server mendaur ulangnya gagal pada penggunaan berikutnya. Konfigurasikan ConnMaxLifetime dan ConnMaxIdleTime agar merotasi koneksi sebelum koneksi tersebut menjadi usang:
// 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
Saat ConnMaxIdleTime menutup koneksi menganggur secara proaktif, log di SQL Server mungkin menunjukkan bahwa koneksi terputus. Ini adalah perilaku yang diharapkan, bukan kebocoran koneksi. Jika DBA Anda melaporkan penutupan koneksi yang tidak terduga, verifikasi bahwa ConnMaxIdleTime pengaturan tersebut selaras dengan ekspektasi pemantauan tim.
Jika aplikasi Anda terhubung melalui penyeimbang beban atau Azure SQL dengan replikasi geografis, atur ConnMaxLifetime ke 5 menit atau kurang. Pengaturan ini memastikan koneksi didistribusikan ulang di seluruh replika setelah failover.
Memvalidasi konektivitas saat startup
Selalu panggil db.PingContext setelah membuka database untuk mengonfirmasi string koneksi sudah benar dan server dapat dijangkau:
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)
}
Mengekspor metrik kumpulan
Ekspos statistik kumpulan ke sistem pemantauan Anda dengan membaca db.Stats()secara berkala :
Contoh Prometheus
Daftarkan pengukur yang melacak statistik kumpulan dan memperbaruinya secara berkala:
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
}
}
}
Daftar periksa konfigurasi kumpulan
| Area | Recommendation |
|---|---|
MaxOpenConns |
Selalu atur ke nilai terbatas. Sesuaikan dengan tingkat konkurensi beban kerja Anda, agar tetap di bawah batas koneksi server. |
MaxIdleConns |
Tetapkan setidaknya separuh dari MaxOpenConns. Terlalu sedikit koneksi idle menyebabkan overhead akibat penyambungan ulang yang sering terjadi. |
ConnMaxLifetime |
Atur ke 5 menit untuk Azure SQL atau lingkungan yang seimbang beban. Mencegah penumpukan koneksi yang kedaluwarsa. |
ConnMaxIdleTime |
Atur ke 30-60 detik untuk menutup koneksi yang tidak lagi diperlukan. |
| Monitoring | Lakukan polling pada db.Stats() dan buat peringatan untuk peningkatan WaitCount. |
| Pembersihan sumber daya | Selalu defer rows.Close(), defer tx.Rollback(), dan defer conn.Close(). |
| Validasi startup | Hubungi db.PingContext setelahnya sql.Open untuk memverifikasi konektivitas. |