Golang应用运行一段时间后崩溃的原因排查

Golang应用运行一段时间后崩溃的原因排查 我正在开发一个网络项目,但每周都会出现数小时的停机时间,现在应用程序频繁崩溃。

我检查了所有服务器日志,在MySQL连接中发现了问题:

2018-02-28T12:00:01.963958Z 402 [Note] Aborted connection 402 to db: 'username' user: 'root' host: 'localhost' (Got an error reading communication packets)
2018-02-28T12:00:01.963958Z 255 [Note] Aborted connection 255 to db: 'username' user: 'root' host: 'localhost' (Got an error reading communication packets)
2018-02-28T12:00:01.963992Z 252 [Note] Aborted connection 252 to db: 'username' user: 'root' host: 'localhost' (Got an error reading communication packets)
2018-02-28T12:00:01.964148Z 248 [Note] Aborted connection 248 to db: 'username' user: 'root' host: 'localhost' (Got an error reading communication packets)
2018-02-28T12:00:01.964018Z 249 [Note] Aborted connection 249 to db: 'username' user: 'root' host: 'localhost' (Got an error reading communication packets)

我认为这是应用程序崩溃的原因,因为MySQL连接正在中止。

能否请您指出我做错了什么,以及为什么会有这么多连接?

谢谢


更多关于Golang应用运行一段时间后崩溃的原因排查的实战教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

我只是个初学者。但根据我的经验,我建议尝试更换端口。因为有时使用相同的端口无法连接到数据库。

更多关于Golang应用运行一段时间后崩溃的原因排查的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你好Adriel,

感谢回复。我在MySQL官网也看到了这个信息。

我会再进一步查证。

谢谢

andersk: 在一个网络项目中,但它每周有数小时的停机时间,现在经常崩溃。

你的GO代码是否直接连接到mysql? 如果是这样,你能告诉我们你正在使用哪些sql包并发布相关代码吗?(当然不包括密码)

当在数据库中执行查询后,应该关闭该引用变量

例如:

dB ,err := connection.Query(" ur query ")
If errs := dB.error ; errs!=nill{
dB.close()
}

你也可以处理错误

andersk,在调试代码之前我想分享这个情况:

MySQL会增加Aborted_clients的状态计数器,这可能意味着:

  • 客户端成功连接但异常终止(可能与未正确关闭连接有关)
  • 客户端休眠时间超过了定义的wait_timeout或interactive_timeout秒数(最终导致连接休眠wait_timeout秒后,被MySQL服务器强制关闭)
  • 客户端异常终止或查询超过了max_allowed_packet限制

还有其他人认为这与网络/防火墙有关。

从MySQL日志看,连接被中止(“Aborted connection”)通常是因为客户端(你的Go应用)没有正确关闭数据库连接,导致连接泄漏。当连接池耗尽或达到MySQL的max_connections限制时,新请求无法建立连接,可能引发应用崩溃。

在Go中,常见原因是未调用rows.Close()db.Close(),或未使用连接池配置。以下是一个修复示例:

package main

import (
    "database/sql"
    "log"
    "time"

    _ "github.com/go-sql-driver/mysql"
)

func main() {
    db, err := sql.Open("mysql", "root:@tcp(localhost:3306)/username")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close() // 确保应用退出时关闭连接

    // 配置连接池以避免泄漏
    db.SetMaxOpenConns(25)
    db.SetMaxIdleConns(25)
    db.SetConnMaxLifetime(5 * time.Minute)

    // 查询示例:必须关闭rows
    rows, err := db.Query("SELECT id FROM users")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close() // 关键:防止连接泄漏

    for rows.Next() {
        var id int
        if err := rows.Scan(&id); err != nil {
            log.Fatal(err)
        }
        // 处理数据
    }
    if err := rows.Err(); err != nil {
        log.Fatal(err)
    }
}

关键点:

  1. 使用defer rows.Close()确保查询后释放连接。
  2. 设置连接池参数(SetMaxOpenConns等)限制并发连接数。
  3. 检查代码中所有数据库操作是否都正确关闭了连接。

此外,检查MySQL的wait_timeout设置:如果超时时间较短,而Go应用未及时释放空闲连接,MySQL会主动断开连接,导致错误。确保连接池的SetConnMaxLifetime小于MySQL的wait_timeout(默认8小时)。

使用db.Stats()监控连接池状态,确认是否有泄漏:

// 定期打印连接统计
log.Printf("DB Stats: %+v", db.Stats())

如果问题持续,使用pprof分析内存和goroutine,检查是否有未释放的资源。

回到顶部