【严重生产事故】执行DDL导致的灾难

278 阅读3分钟

前言

12月19日晚,项目组准备发布新版本,在执行SQL(DDL语句)的时候,生产环境大量接口报错,甚至阻塞了核心交易链路。

不一会功夫,飞书工作群立马炸开了锅,各种投诉和问责接踵而至.....

事故过程回顾

  1. 19日17:00,开发人员和DBA(数据库管理员)沟通本次版本执行SQL(DDL)对系统的影响,估算执行时间为几分钟,因为之前执行过类似语句
  2. 19日17:30,开发人员提交SQL工单,DBA审批通过,SQL待手动执行
  3. 19日21:35,开发人员手动执行SQL
  4. 19日21:40,生产环境开始出现大量告警和用户反馈故障,此时SQL还在执行中
  5. 19日21:52,SQL还在执行中,DBA直接杀死SQL执行进程
  6. 19日21:55,生产环境逐步恢复正常

事故原因分析

数据库在执行DDL的时候,发生了锁表,阻塞了大量正常业务的增删改查,大量线程在等待锁,接着dubbo线程池被打满,最终导致生产环境大批系统故障,下图是当时生产环境的日志:

image.png

此外,执行SQL的时间为晚上21:35,这个时间并非系统流量低峰期,数据库需要处理大量用户的请求;而且,本次操作的表还是张大表,数据量上千万,无疑给DDL增加了难度和风险。

本次DDL的执行方式为直接执行SQL,生产环境MySQL版本为5.7,也就是说最终使用的是MySQL自带的Online DDL机制,这种机制有可能会阻塞DML语句(数据增删改查)。

Online DDL为什么会锁表

执行DDL的方式有哪些

对于MySQL 5.5,执行DDL会阻塞DML语句。

到了MySQL 5.6,官方引入了Online DDL,顾名思义是可以在线上环境执行的一种方式,但是不代表它完全不会阻塞DML。

后来又衍生了一些第三方DDL工具,如pt-osc、github的gh-ost,它们相比较MySQL自带的方式更加安全。

Online DDL的具体执行流程

对于MySQL 5.7,Online DDL 包含了 copy 和 inplace 两种算法。

copy算法就跟MySQL 5.5一样会全程阻塞DML。

对于inplace算法,执行过程中会有小部分时间获取MDL写锁造成阻塞DML。 与此同时,还区分两类方式,一类需要重建表(重新组织记录),比如 optimize table 、添加索引、添加/删除列、修改列 NULL / NOT NULL 属性等;另外一类只需要修改表的元数据,比如删除索引、修改列名、修改列默认值、修改列自增值等。MySQL 将这两类方式分别称为 rebuild 方式和 no-rebuild 方式。

Online DDL过程包括3个阶段,prepare阶段、ddl执行阶段、commit阶段,具体流程如下图所示。通常情况下,在prepare和commit阶段占用MDL写锁(图中exclusive-mdl锁)的时间会非常短,但是如果是面对大表DDL或者是增删改查比较频繁的情况下,发生异常的风险增大,可能会造成长时间阻塞DML。

image.png


总结

  1. DDL需要在系统流量低峰期执行,尤其是大表
  2. MySQL 5.7的Online DDL机制会用到MDL写锁,因此有阻塞DML的可能
  3. 面对复杂情况,想采取更安全的手段,可以使用DDL操作工具如pt-osc、github的gh-ost


参考

MySQL 5.7 官方文档 dev.mysql.com/doc/refman/…

juejin.cn/post/723876…