mysql 代替不明_所有的死锁,都是不明就里的循环。又一必须升级MySQL的死锁问题!!!...

原标题:所有的死锁,都是不明就里的循环。又一必须升级MySQL的死锁问题!!!

e7d67ea76a8d64774b2039eb9353c534.png

去年年底到今年年初,线上发生了3次MySQL数据库hang住的情况。在内部,我们将其称为半死不活的场景。具体的表现表现如下:

从机telnet探活主机是存活(alive)状态;

主机SELECT 1心跳是好的;

业务所有的数据库访问都处于hang住状态 ;

因为在之前的切换判断中,主机有心跳,从机也上报主机活着,所以这种场景数据库并不会进行切换。有同学会问,为什么不用REPLACE进行判断?因为即使用REPLACE判断,这时也无法返回,连接是被hang住的。(BTW,我们有另一套业务维度的切换逻辑,这里先不展开)

现在的问题是,为什么MySQL数据库被hang住?DBA的反馈是主机SSD卡的问题。嗯,显然,这是一个非常明显DBA风格的结论,即将锅甩给硬件。想想DBA也煞是可怜,每每遇到问题都是背锅侠,遇到自己解决不了的问题,只能丢给硬件厂商。

可惜可惜,我们的系统有磁盘健康度的定期探测逻辑,一切显示那时磁盘工作得好好滴。好在还是有乐意深究的同学,当最近再次发生同样问题时,他用工具pstack进行追踪,终于在bug库中定位到了问题。

这是一个典型的内部latch死锁问题。 如果能对MySQL进行连接,并且执行SELECT 1,但是执行其他有关表的操作,都会hang住,这就是latch死锁。这类问题对于Oracle出身的DBA来说就是两手一摊,无能为力,吐槽到MySQL bug。但具体原因,又说不出啥。然而,对于真正的MySQL DBA来说,这简直就是piece of breeze~~~

开个gdb,打印一些堆栈信息,对照关键函数,翻阅一点源码吗,done。然后,麻烦立即去朋友圈、微博装逼。你是说我在装么?拜托,我是让发现问题的同学装逼完一轮,才将文章发出来的。姜老师,不会抢任何人的功劳。

这个latch死锁问题的原因是,当有三个线程并行执行下面的SQL语句时,有可能会导致latch死锁的问题:

SHOW BINARY LOGS

SHOW VARIABLES / SELECT performance_schema.session_variables

PURGE BINARY LOGS TO 'xxx.yyy'

命令SHOW BINARY LOGS是因为有后台监控线程定期会收集MySQL的二进制日志的大小和增量。

命令SHOW VARIABLES是因为我们会进行主从参数的一致性校验,因此会对参数进行定期探测与校验。

命令PURGE BINARY LOGS TO是因为需要定期删除二进制日志,确保磁盘空间可用。

所有上述操作,是非常例行的后台线程操作,然而这却有概率导致latch死锁。如果你用工具打印当时hang住的线程,并进行分析时,会发现存在下面的循环:

754837c95916b84a6c1ae27a007a02cc.png

是啊, 所有的死锁,都是不明就里的循环。在弄清楚这个循环依赖图后,问题就显得清晰多了。现在第二个问题是命令SHOW VARIABLES时,为什么要持有锁LOCK_log?

仔细看堆栈信息并结合源码,发现只有在查询参数binlog_transaction_dependency_tracking、binlog_transaction_dependency_history_size时才会使用LOCK_log加锁,这也解释了为什么数据库在升级到MySQL 5.7.24版本之后,线上会遇到hang住的问题。

staticSys_var_enum Binlog_transaction_dependency_tracking(

"binlog_transaction_dependency_tracking",

......

DEFAULT(DEPENDENCY_TRACKING_COMMIT_ORDER), & PLock_log,

NOT_IN_BINLOG, ON_CHECK(check_binlog_transaction_dependency_tracking),

ON_UPDATE(update_binlog_transaction_dependency_tracking));

引申到第三个问题,为什么上述两个参数,需要加锁LOCK_log,感觉没有直接关系?第三个问题非常核心,需要理解锁LOCK_log的使用。简单来说, 所有关于二进制日志的操作,都需要持有锁LOCK_log的保护。

在事务提交过程时,会调用函数MYSQL_BIN_LOG::ordered_commit,其中有个步骤是将当前的gtid写入到二进制日志文件,这里面会写入last_committed值,而这个值与参数binlog_transaction_dependency_tracking对应的值COMMIT_ORDER、WRITESET、WRITESET_SESSION有密切相关性。因此,在读取/修改参数binlog_transaction_dependency_tracking时,需要锁LOCK_log保护,避免事务提交时写入错误的last_committed值。

到此为止,这个问题算是彻底地定位了。要解决这个问题也变得比较简单,通过引入新的latch LOCK_slave_trans_dep_tracker来保护参数binlog_transaction_dependency_tracking、binlog_transaction_dependency_history_size即可。具体官方修复代码请点击下方 阅读原文。线上生产环境的话,请尽快升级到5.7.25、8.0.14的版本(或之后的版本)。

看完上述这个问题,理解后再复盘下,看看自己是否都已完全掌握:

MySQL latch死锁的表现现象是怎样的?

产生latch死锁的原因是什么? 画出死锁循环图

为什么会产生死锁?如何避免死锁?

为什么死锁还与参数binlog_transaction_dependency_history_size有关?

最后的最后,其实我想吐槽下MySQL Server层的代码,写得太烂太烂,简直就是应届生的代码风格,而且对于latch锁与并发的理解都算非常非常不到位,当然这有历史原因。

然而回过头来看,最最主要的原因,个人还是觉得Monty当时的代码能力是偏弱的,远远不及InnoDB创始人Heikki Tuuri的代码组织和对数据库本身知识的掌握。在InnoDB层里,有对每一个latch锁的优先级定义,打开DEBUG选项,可以判断加锁的优先级和准确性,在编译和调试阶段就能非常轻易地发现这样简单的死锁场景。

印象中InnoDB只有早年IB有死锁的问题,而MySQL Server层简直是修复不完的死锁场景 ~~~哎,一声叹气,或许这就是底层人的悲哀吧~~~

//

长期坚持原创真的很不容易,多次想放弃。坚持是一种信仰,专注是一种态度!打赏和点击在看是对作者最好的褒奖哟~~

PS:想要加入IMG微信技术群的同学(目前仅峨眉群有坑,少林、武当两群已满),可私信我微信82946772,备注:申请加入峨眉,猎头勿扰。

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值