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

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

内容简介:由于我们用的是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,一直阻塞着。

  • 完结~

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

查看所有标签

猜你喜欢:

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

数学之美 (第二版)

数学之美 (第二版)

吴军 / 人民邮电出版社 / 2014-11 / 49.00元

几年前,“数学之美”系列文章原刊载于谷歌黑板报,获得上百万次点击,得到读者高度评价。读者说,读了“数学之美”,才发现大学时学的数学知识,比如马尔可夫链、矩阵计算,甚至余弦函数原来都如此亲切,并且栩栩如生,才发现自然语言和信息处理这么有趣。 在纸本书的创作中,作者吴军博士几乎把所有文章都重写了一遍,为的是把高深的数学原理讲得更加通俗易懂,让非专业读者也能领略数学的魅力。读者通过具体的例子学到的......一起来看看 《数学之美 (第二版)》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具