事件起因:生产环境的mysql从库突然访问巨慢,且mysql的连接线程数飙升。
1. 问题原因
问题复现流程:
- 由于是mysql主从同步(查询操作在从库执行),alter操作在主库执行完毕后,将同步到从库执行alter操作。
- 但是某个项目正在使用
flink
查询从库select * from a
操作(但是加了事务注解)。【因为这个事务方法及其耗时,便一直持有着数据库连接】。 - alter操作发现有数据库连接在执行,会被阻塞;
- 从库中所有a表的sql语句(包含无事务的select)都被阻塞,等待alter执行。导致后续的a表的主从同步和查询功能都被阻塞,使得mysql连接线程数飙升。
- 连接线程数飙升后,导致mysql的从库访问巨慢,造成从库瘫痪,影响业务。
alter操作等待事务提交,其他操作等待alter执行完毕,最终造成死锁。
问题解决方案:
将select * from a
的事务移除。
问题分析:
因为,会阻塞DDL语句的执行。而mysql发现阻塞队列中存在DDL语句时,为了防止执行的DML语句执行失败或者未查询出新增的字段,也会阻塞DML语句。由此会使得操作该表的数据库线程均被阻塞。从而导致整个数据库崩溃。
问题复现
用户1:开启事务查询某个表。该数据库连接一直被持有:
image.png用户2:执行DDL语句,发现被阻塞:
image.png用户3:模拟主从同步,或者单纯的查询操作,发现线程也会被阻塞:
image.png2. 问题教训
- 加事务还是要谨慎,粒度要及其小。
- DDL语句尽量不要在访问高峰期进行操作!
- DDL执行时机需要有人监管!
-----------------------------------------------分界线
2021.6.21
3. 问题再现
某天凌晨12点执行ddl语句,主库再次被阻塞。
经过DBA排查后,发现是phpAdmin执行的一条select语句,却一直存在于mysql主库的服务器中(已经存在一个月)。导致数据库连接一直被持有。再次阻塞ddl语句,而ddl语句阻塞其他的sql语句,造成系统崩溃。
3.1 问题复现:
查询数据库存在的进程:
show processlist;
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锁等待。
网友评论