现像
第三方平台调用我方平台接口后导致服务不可用,数据库大量sleep线程,请求数据库无响应;数据库及代码无任何报错,无法定位问题。第三方接口首次请求并不会触发该问题。
运行环境
开发语言:golang v1.19
数据库:mysql8
线索搜集
1、对mysql的操作,使用了连接池,并在使用连接之前,调用goalng mysql 的 Ping()检查连接是否可用;
2、发生问题接口的地方使用了事务,开启事务的代码如下:
func (q *ExQuery) CreateDBTx() (*ExQuery, error) {
ctx := context.Background()
q.Ctx = ctx
conn, e := q.DB.Conn(ctx)
if e == nil {
opts := new(sql.TxOptions)
tx, err := q.DB.BeginTx(ctx, opts)
if err == nil {
q.Tx = tx
return q, nil
} else {
return nil, err
}
}
log.Println("===创建事务失败:===", e)
return nil, e
}
3、show processlist发现连接一直增加并未释放,大量sleep线程;
思路
1、首先要找到大量连接未释的原因;
2、其次解决死锁;
发现问题
// 查阅开启事务方法时发现
// conn, e := q.DB.Conn(ctx)
// 会新建连接,但在代码中未关闭,但此又处不能关闭,关闭后,连接断开,线程中的查询无效
// 而后将此段代码修改为:
func (q *ExQuery) CreateDBTx() (*ExQuery, error) {
ctx := context.Background()
q.Ctx = ctx
// conn, e := q.DB.Conn(ctx)
// if e == nil {
opts := new(sql.TxOptions)
tx, err := q.DB.BeginTx(ctx, opts)
if err == nil {
q.Tx = tx
return q, nil
} else {
return nil, err
}
// }
log.Println("===创建事务失败:===", err)
return nil, err
}
大量连接未释放问题解决完毕
golang mysql Ping() 此方法在mysql连接不足(因为上面大量sleep)时会永久阻塞;用以前方法替代:
connerr := dbConnection.DB.PingContext(ctx)
阻塞问题解决
以此记录
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。