记一次gorm连接池打满,连接不释放的问题(Remember the problem that the Gorm connection pool is full and the connection is not released)

概述:使用事务一定要关闭!(心急的可以直接看这句,赶紧去检查下自己的代码)

  我们golang项目用的gorm,最近pre测试跑脚本时,总会出现504,某个接口不可用。分析了半天pprof,阻塞数量较多的goroutine,某些时候并不能看到真实问题的所在。

  出现504,通过pprof:debug/pprof/goroutine?debug=2 或者debug/pprof/goroutine?debug=1 能看到阻塞的goroutine,处在io wait状态  检查下pod内,连接数(netstat),发现http的连接数和mysql的连接数暴增!!!  导致mysql的连接数暴增常见的有两种:  1、使用事务,没有关闭~!!!!! (我们小伙伴的错误命中)     tx:=db.conn后,err判断,直接return,没有进行tx.rollback。这时候mysql的conn_pool会+1,且不可复用。     错误的请求继续上涨后,就会出现连接数打满,继而新的请求一直阻塞,goroutine也会阻塞住   正确使用:

conn, err := mysql.GetConn()
if err != nil {
    return
}
tx := conn.Begin()
    defer func() {
        if r := recover(); r != nil {
        tx.Rollback()
    }
}()
if err != nil {
    tx.Rollback()
    return
}        

2、使用rows方法请一定要关闭连接。rows请一定要在err==nil的情况下使用,不然会导致空指针panic。

rows, err := db.rows()
if err != ni {
    return err
}
defer rows.close()

3、使用事务,切记

tx := conn.Begin()下面一定使用tx,不要用conn了!!!!
————————

Overview: use transactions must be closed! (if you are anxious, you can look at this sentence directly and check your code quickly)

The Gorm used in our gorang project always shows 504 when running the script in the pre test recently, and an interface is unavailable. After analyzing the half day pprof, goroutine with a large number of blocking can not see the real problem in some cases.

504 appears through pprof: debug / pprof / goroutine? Debug = 2 or debug / pprof / goroutine? When debug = 1, you can see the blocked goroutine. In the IO wait state, check the number of connections (netstat) in the pod. It is found that the number of HTTP connections and MySQL connections has soared!!! There are two common reasons for the sharp increase in the number of MySQL connections: 1. Using transactions without closing ~!!!!! (our little partner’s wrong hit)     tx:=db. After Conn, err judges and returns directly without tx.rollback. At this time, MySQL conn_ Pool will be + 1 and cannot be reused. After the wrong request continues to rise, the number of connections will be full, and then the new request will be blocked all the time, and the goroutine will also be blocked Correct use:

conn, err := mysql.GetConn()
if err != nil {
    return
}
tx := conn.Begin()
    defer func() {
        if r := recover(); r != nil {
        tx.Rollback()
    }
}()
if err != nil {
    tx.Rollback()
    return
}        

2. Be sure to close the connection when using the rows method. Rows must be used when err = = nil, otherwise it will cause the null pointer panic.

rows, err := db.rows()
if err != ni {
    return err
}
defer rows.close()

3. When using transactions, remember

tx := conn.Begin()下面一定使用tx,不要用conn了!!!!