現象
伺服器pprof中的goroutines 很多,無法釋放,肯定是異常.
程式碼
// 收到 請求上個賽季個人秘境賽季排行
func (this *MsgProc) MsgProc_PersonSecretLastRankReq(msg *protoMsg.PersonSecretLastRankReq) {
global.GetSrvInst().GetThreadGo().Go(func(ctx context.Context) {
global.GetSrvInst().GetMysqlConn().Transaction(func(tx *gorm.DB) error {
// 拿到當前資料
var mynode *protoMsg.PersonSecretRankMD
global.GetSrvInst().GetMysqlConn().Where("seasonid=? and pid=?", msg.SeasonID, msg.PID).Find(&mynode)
if mynode == nil || mynode.SeasonID == 0 || mynode.PID == 0 {
// 空資料
server.PostPlayerSrv(msg.PID, gcommon.ServerTypeLobby, &protoMsg.PersonSecretLastRankRet{
LastSeasonID: msg.SeasonID,
PID: msg.PID,
LastSeasonRank: 0,
})
return nil
}
server.PostPlayerSrv(msg.PID, gcommon.ServerTypeLobby, &protoMsg.PersonSecretLastRankRet{
LastSeasonID: msg.SeasonID,
PID: msg.PID,
LastSeasonRank: mynode.SeasonRank,
LastSeasonEndTime: mynode.UpdatedAt.Unix(),
})
return nil
})
})
}
結論
在gorm的transaction中, Begin會申請一個conn連結, 然後內部如果在獲取新的Mysql Conn的話, 當conn達到maxNum的時候,就會卡住, transaction無法自動釋放conn,進而導致雪崩,其他的程式碼想要呼叫mysql都會出現等待conn的死鎖情況.
所以 在 transaction 的程式碼中, 要用 tx 物件,不要用新的物件.
ps: 這程式碼是同事寫的,但是引以為戒. 順便 get 到gorm事務的踩坑用法,知道為什麼這麼寫更重要.