惊!mysql表新增表字段时造成死锁—造成数据库瘫痪!!!(Waiting for table metadata lock的原因以及解决方法)

事件起因:生产环境的mysql从库突然访问巨慢,且mysql的连接线程数飙升。

1. 问题原因

问题复现流程:

  1. 由于是mysql主从同步(查询操作在从库执行),alter操作在主库执行完毕后,将同步到从库执行alter操作。
  2. 但是某个项目正在使用flink查询从库select * from a操作(但是加了事务注解)。【因为这个事务方法及其耗时,便一直持有着数据库连接】
  3. alter操作发现有数据库连接在执行,会被阻塞;
  4. 从库中所有a表的sql语句(包含无事务的select)都被阻塞,等待alter执行。导致后续的a表的主从同步和查询功能都被阻塞,使得mysql连接线程数飙升。
  5. 连接线程数飙升后,导致mysql的从库访问巨慢,造成从库瘫痪,影响业务。

alter操作等待事务提交,其他操作等待alter执行完毕,最终造成死锁。

问题解决方案:

select * from a的事务移除。

问题分析:

因为,会阻塞DDL语句的执行。而mysql发现阻塞队列中存在DDL语句时,为了防止执行的DML语句执行失败或者未查询出新增的字段,也会阻塞DML语句。由此会使得操作该表的数据库线程均被阻塞。从而导致整个数据库崩溃。

问题复现

用户1:开启事务查询某个表。该数据库连接一直被持有:

惊!mysql表新增表字段时造成死锁—造成数据库瘫痪!!!(Waiting for table metadata lock的原因以及解决方法)_第1张图片
image.png

用户2:执行DDL语句,发现被阻塞:

惊!mysql表新增表字段时造成死锁—造成数据库瘫痪!!!(Waiting for table metadata lock的原因以及解决方法)_第2张图片
image.png

用户3:模拟主从同步,或者单纯的查询操作,发现线程也会被阻塞:

惊!mysql表新增表字段时造成死锁—造成数据库瘫痪!!!(Waiting for table metadata lock的原因以及解决方法)_第3张图片
image.png

2. 问题教训

  1. 加事务还是要谨慎,粒度要及其小。
  2. DDL语句尽量不要在访问高峰期进行操作!
  3. DDL执行时机需要有人监管!

-----------------------------------------------分界线
2021.6.21

3. 问题再现

某天凌晨12点执行ddl语句,主库再次被阻塞。

经过DBA排查后,发现是phpAdmin执行的一条select语句,却一直存在于mysql主库的服务器中(已经存在一个月)。导致数据库连接一直被持有。再次阻塞ddl语句,而ddl语句阻塞其他的sql语句,造成系统崩溃。

3.1 问题复现:

查询数据库存在的进程:

show processlist;
惊!mysql表新增表字段时造成死锁—造成数据库瘫痪!!!(Waiting for table metadata lock的原因以及解决方法)_第4张图片
image.png

不仅是事务操作,单纯的大的select操作也会阻塞ddl语句。

一个大的select操作。查询事务:

SELECT * FROM information_schema.INNODB_TRX
image.png

结论:单纯的select * from table where id =1也存在事务。

事务是多个sql语句共有一个数据库连接,而单条的select语句也是一个数据库连接。

alter table的语句是很危险的(其实他的危险其实是未提交事物或者长事务导致的),在操作之前最好确认对要操作的表没有任何进行中的操作、没有未提交事务、也没有显式事务中的报错语句。如果有alter table的维护任务,在无人监管的时候运行,最好通过lock_wait_timeout设置好超时时间,避免长时间的metedata锁等待。

推荐阅读

MySQL出现Waiting for table metadata lock的原因以及解决方法

你可能感兴趣的:(惊!mysql表新增表字段时造成死锁—造成数据库瘫痪!!!(Waiting for table metadata lock的原因以及解决方法))