Golang中connectionOpener goroutine运行1500分钟问题探讨

Golang中connectionOpener goroutine运行1500分钟问题探讨 大家好,

我们在生产环境中遇到了一个内存分配/泄漏问题。添加了PProf后发现,自构建启动以来,有一个SQL goroutine一直处于唤醒状态。

我想知道,当goroutine运行超过1500-1800分钟时,这是否是一个严重问题?

以下是代码片段:

目录结构:

MAIN 文件.GO

Db.GO

Pprof:pprof显示一个名为connectionOpener的goroutine,其运行时间持续增加。

goroutine 19 [select, 1482 minutes]:
database/sql.(*DB).connectionOpener(0xc00049d110, {0xf83e10, 0xc000181a40}) /usr/local/go/src/database/sql/sql.go:1218 +0x8d
created by database/sql.OpenDB /usr/local/go/src/database/sql/sql.go:791 +0x18d

goroutine 26 [select, 1482 minutes]: database/sql.(*DB).connectionOpener(0xc00049c1a0, {0xf83e10, 0xc00011c0f0}) /usr/local/go/src/database/sql/sql.go:1218 +0x8d
created by database/sql.OpenDB /usr/local/go/src/database/sql/sql.go:791 +0x18d
is it normal to have this open for such a long time ?
from https://kumakichi.github.io/goroutine-leak.html seen that we need to close 
 the  connection.but closing the connection 
 using the reference of db is correct ? I mean suspecting the overall structure.
 Kindly help

更多关于Golang中connectionOpener goroutine运行1500分钟问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

你设置了最大连接数吗?

更多关于Golang中connectionOpener goroutine运行1500分钟问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


您的数据库连接不应放在 goroutine 中。 如果您需要数据库连接,应在应用程序启动阶段设置它,我的意思是将其放入您的 main() 函数中。

这是正常的数据库连接池行为。connectionOpener goroutine 是 database/sql 包内部用于异步建立数据库连接的协程,它会一直运行直到数据库连接池关闭。

示例代码展示正确的连接关闭方式:

package main

import (
    "database/sql"
    "log"
    "time"
    _ "github.com/go-sql-driver/mysql"
)

func main() {
    // 打开数据库连接
    db, err := sql.Open("mysql", "user:password@/dbname")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close() // 确保程序退出时关闭连接池
    
    // 配置连接池参数
    db.SetMaxOpenConns(25)
    db.SetMaxIdleConns(25)
    db.SetConnMaxLifetime(5 * time.Minute)
    
    // 使用数据库连接
    rows, err := db.Query("SELECT * FROM users")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()
    
    // 处理查询结果...
}

关键点:

  1. connectionOpener goroutine 会持续运行,这是设计使然
  2. 使用 defer db.Close() 确保程序退出时释放所有资源
  3. 通过 SetConnMaxLifetime 设置连接最大生命周期,避免连接长时间闲置
  4. 每个查询后及时关闭 rows.Close()

如果怀疑内存泄漏,检查:

  • 是否在所有代码路径上都正确调用了 db.Close()
  • 是否每个 Query/Exec 后都调用了 rows.Close()/stmt.Close()
  • 连接池参数配置是否合理

运行时间长的 connectionOpener 本身不是问题,但需要确保连接池被正确管理和最终释放。

回到顶部