记一次MySQL没有Commit Transaction导致的线上事故

栏目: 数据库 · 发布时间: 7年前

内容简介:由于我们用的是golang的gorm,我需要知道数据库的状态。那么我需要加入一个定时任务去打印一下数据库的状态。代码如下:我们可以看到DBStats结构体是这样的,代码如下:
  • 首先如何复现BUG,只能让服务跑几天,出现bug才能检查。
  • 果不其然,今天BUG再次出现。

② 定位BUG

  • 1、能正常访问视图的Route,访问Route,产生的HTTP Log也能打印。
  • 2、Crontab Jobs 都无法执行,Log也无法打印。
  • 3、有一个打印第三方API状态的定时任务没有挂
  • 4、综上,是所有访问数据库的操作都阻塞了。那么应该从数据库操作查起。

③解决

由于我们用的是golang的gorm,我需要知道数据库的状态。那么我需要加入一个定时任务去打印一下数据库的状态。代码如下:

func main(){
    
    err := c.AddFunc("@every 5s", func() {
        by, _ := json.Marshal(db.DB.DB().Stats())
        log.Println(string(by))
    })
    if err != nil {
        log.Fatalln(err.Error())
        return
    }
    
}

我们可以看到DBStats结构体是这样的,代码如下:

// DBStats contains database statistics.
type DBStats struct {
	MaxOpenConnections int // Maximum number of open connections to the database.

	// Pool Status
	OpenConnections int // The number of established connections both in use and idle.
	InUse           int // The number of connections currently in use.
	Idle            int // The number of idle connections.

	// Counters
	WaitCount         int64         // The total number of connections waited for.
	WaitDuration      time.Duration // The total time blocked waiting for a new connection.
	MaxIdleClosed     int64         // The total number of connections closed due to SetMaxIdleConns.
	MaxLifetimeClosed int64         // The total number of connections closed due to SetConnMaxLifetime.
}
  • 那么问题来了,加入定时任务打印数据库状态后,我发现InUse居然占满了,WaitCount也在不断增加。看下面的JSON数据:
{"MaxOpenConnections":30,"OpenConnections":30,"InUse":30,"Idle":0,"WaitCount":18032,"WaitDuration":66343149623,"MaxIdleClosed":0,"MaxLifetimeClosed":4203}


{"MaxOpenConnections":30,"OpenConnections":30,"InUse":30,"Idle":0,"WaitCount":179968,"WaitDuration":5069116627810,"MaxIdleClosed":0,"MaxLifetimeClosed":5147}
  • 那么基本可以确定问题了,大概就是从连接池里面取到连接,用完后没放回池子里面,或者是持续占用着连接。

  • 由于API和jobs里面都涉及到了数据库操作。那么什么样的操作会导致连接一直占用呢,我第一可能想到的就是Transaction没有Commit或者Rollback了。

  • 果不其然,找到了以下代码,那一刻真想打死自己~ ‍♂️ ‍♂️ ‍♂️ ‍♂️ ‍♂️ ‍♂️ ‍♂️ ‍♂️ ‍♂️ ‍♂️ ‍♂️ ‍♂️

tx := o.Begin()
transactionIsOk, err := chain.EthChainInstance.GetTransactionReceipt(action.Hash)
if err != nil {
    continue
}
  • 更改后的代码
tx := o.Begin()
transactionIsOk, err := chain.EthChainInstance.GetTransactionReceipt(action.Hash)
if err != nil {
    tx.Rollback()
    continue
}
  • 其实更建议的是用 defer tx.Commit() 或者 defer tx.Rollback()

  • 由于Transaction没有结束,所以会一直占用着连接,导致InUse占满OpenConnections,并且使得其他的数据库操作在连接池里取得连接的时候,无法执行相应的SQL,一直阻塞着。

  • 完结~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

Understanding Machine Learning

Understanding Machine Learning

Shai Shalev-Shwartz、Shai Ben-David / Cambridge University Press / 2014 / USD 48.51

Machine learning is one of the fastest growing areas of computer science, with far-reaching applications. The aim of this textbook is to introduce machine learning, and the algorithmic paradigms it of......一起来看看 《Understanding Machine Learning》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具