首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >吓尿,给小表加个字段,把数据库搞挂了

吓尿,给小表加个字段,把数据库搞挂了

作者头像
会玩code
发布于 2022-04-24 14:08:29
发布于 2022-04-24 14:08:29
8430
举报
文章被收录于专栏:会玩code会玩code

一天下午,在给线上一个小表加个字段,发现老是加不上去,一直卡死。运维同学突然跑过来跟我说,线上数据库这半个小时一直在重启,问我是否有做什么操作。我当时虎躯一震,总共 100 多行的小表加个字段都加出问题了?我立马停止尝试加字段,果然数据库恢复正常了。后面查到原因,也顺利加上字段,现在来复盘总结一下。

先讲下原因,表数据量虽然小,却是一个热点表,访问频率特别高,而且该表的访问是在一个大事务中。加字段的时候一直在等待获取 MDL 写锁。这个等待也影响了后续表访问对 MDL 读锁的获取,导致后面的查询也都被堵塞了。更惨的是,客户端有重试机制,查询堵塞超过超时时间会再起一个 session 进行请求,导致数据库的线程池很快就爆满了,直接挂掉。

什么是 MDL 锁

MDL 锁属于表级别的元数据锁。表级别锁分为数据锁和元数据锁,通常我们说的加锁一般指的是加的数据锁。跟数据锁一样,元数据锁也分读锁和读写锁。

MDL 不需要显示使用,在进行表操作时会自动加上。当对表进行增删改查时,会自动加上 MDL 读锁;当要对表进行加减字段的结构修改时,会自动加上 MDL 写锁。

  • 读锁不互斥,意味着可以多个线程同时对一张表进行增删改查的操作。
  • 写锁独占,进行结构修改前,要先等待其他所有的 MDL 锁释放了才能获取到 MDL 写锁。获取到写锁后,在写锁释放前,其他线程无法获取到 MDL 读锁和写锁。也就是说,修改一个表的结构过程中,会阻塞其他线程对表的操作。

MDL 锁的必要性

MDL 锁的存在,其实是为了保证数据的一致性。想象一下,假如没有 MDL 锁,一个查询在遍历表数据的过程中,另外一个线程执行了 ALTER TABLE t DELETE COLUMN 'col_1' 把 col_1 这一列删掉了,那查询结果就乱了,结果中是否应该有这一列数据?

事故复现

介绍完 MDL 锁,我们再来复现下事故。我们通过下面的操作序列来模拟线上情况。

时刻 1,事务 1 对表 t_mdl_test 进行查询,注意此时事务 1 并未提交,所以获取的 MDL 读锁也不会释放。时刻 2 另外一个线程想要添加字段 c, 由于事务 1 正持着 MDL 读锁,所以事务 2 会陷入阻塞,等待事务 1 释放读锁后获取 MDL 写锁。

申请 MDL 锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。所以事务 2 不仅阻塞了加字段的操作,也会阻塞后续对该表的所有操作。比如后面的事务 3 和事务 4 查询由于获取不到 MDL 读锁都被阻塞了。

这时,如果客户端有重试机制,查询超时后会重新进行请求,容易把数据库的连接池给挤爆了。

表 t_mdl_test 建表:

代码语言:javascript
复制
CREATE TABLE `t_mdl_test` (
 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id',
 `a` varchar(64) NOT NULL,
 `b` varchar(64) NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8;

解决办法

了解了原因,事情就比较好办了,数据库奔溃原因是由于加字段等待时间太长导致影响后续请求,但 mysql 又无法在 alter table 语句里面设定等待时间.

所以当时做法是继续尝试加字段语句,语句卡住 30 秒就手动 cancel 掉。避免对后续请求的影响。重试了几次发现一直没能加上。。。,最后是通过查看接口调用监控,在请求频率较低的时间点给加上了。

反思

  1. 避免写大事务,如果不是查询所在的事务太大,也不会导致后面语句获取不到 MDL 写锁。
  2. 事务中,尽量减少加锁时间。还是这次这个例子,从 t_mdl_test 中获取的数据在事务最后一步更新其他表的时候才会用到,所以可以把 t_mdl_test 的查询放在事务的尾部。减少 t_mdl_test 加锁时间。
  3. 对表结构修改的语句注意执行时间,长时间卡住需要注意先取消掉,避免影响其他线程对表的增删改查操作。

留个小问题

在查阅资料的时候,发现另外一个情况。

这种情况事务 2 会阻塞吗?大家可以在自己的 huiwan_write_x 库中自行实验。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-27,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 什么是 MDL 锁
  • MDL 锁的必要性
  • 事故复现
  • 解决办法
  • 反思
  • 留个小问题
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档