当前位置: 首页 > news >正文

一次慢改表引发的线上死锁事故复盘

一次慢改表引发的线上死锁事故复盘

一、事故背景

在一次常规的数据库表结构变更过程中,对某核心业务表执行了慢改表操作(使用 pt-online-schema-change)。操作开始后,短时间内触发报警:

  • 部分接口响应时间显著上升
  • 出现请求超时
  • 影响约千级请求

整个故障持续时间较短(约几十秒),通过手动干预终止异常事务后恢复。


二、事故经过(简要)

  • 11:22:38:执行慢改表
  • 11:22:40:发现接口延迟升高
  • 11:22:45:尝试中断操作,但响应延迟
  • 11:22:50:排查数据库,发现长事务并手动终止
  • 11:23:09:系统恢复正常

三、直接原因

在执行慢改表前,未检查数据库中是否存在长事务,导致:

慢改表过程中无法获取必要的锁资源,从而进入锁等待,最终引发类似死锁的阻塞现象。


四、什么是“慢改表”

在 MySQL 中,对大表执行 DDL(Data Definition Language 数据定义语言,如ALTER TABLE)通常会带来严重问题:

  • 表锁(metadata lock)
  • 数据重建
  • 业务写入阻塞

因此在生产环境中,通常采用在线变更方案,例如:pt-online-schema-change

其核心思路是:

  1. 创建新表(目标结构)
  2. 在旧表上创建 trigger,同步增量数据
  3. 分批拷贝历史数据
  4. 最终通过 rename 完成切换

整个过程避免了长时间锁表,实现“在线变更”。


五、关键知识点:Metadata Lock(MDL)

这是本次事故的核心。

MySQL 在访问表时,会自动加metadata lock(元数据锁)

  • 普通查询(SELECT) → 持有MDL读锁
  • DDL操作(如 ALTER / CREATE TRIGGER) → 需要MDL写锁

锁冲突规则:

读锁(共享)可以并存 写锁(排他)必须等待所有读锁释放

六、事故根因分析(关键)

1. 长事务的存在

系统中存在未提交的事务,例如:

BEGIN;SELECT*FROMtable;-- 未提交

该事务会长期持有:MDL读锁


2. 慢改表的行为

pt-online-schema-change 在执行过程中需要:创建 trigger(DDL操作) → 需要MDL写锁


3. 冲突产生

此时出现:

操作
长事务MDL读锁
pt-oscMDL写锁(等待中)

pt-osc 被阻塞


4. 为什么会影响业务请求

问题并不会停在“阻塞”这一层,而是继续扩大:

  • pt-osc 已经占用部分资源(连接、锁等)
  • 新的业务请求进入数据库
  • 请求开始排队等待锁

最终表现为:

  • 请求RT(Response Time 响应时间)升高
  • 接口超时
  • 系统报警

七、为什么“Ctrl + C”无法立即中断

这是一个常见误区。

MySQL 中:

  • DDL操作(如创建 trigger)
  • 正在等待锁的线程

不会立即响应中断信号

因此:

  • Ctrl + C 可能延迟甚至无效
  • 必须通过KILL或处理阻塞源(长事务)

八、正确的操作流程(慢改表标准 Playbook)

为了避免类似问题再次发生,所有线上慢改表操作必须遵循标准化流程。该流程不仅包含“是否能执行”的判断,还包括“如何安全执行”。

1. 执行前检查(强制步骤)

(1)检查长事务
SELECTtrx_id,trx_started,trx_mysql_thread_id,trx_queryFROMinformation_schema.innodb_trx;

重点关注:

  • 事务运行时间(trx_started)

    • 30秒:需要评估风险

    • 60秒:必须处理

  • SQL内容(trx_query)

    • 全表扫描
    • 大查询
    • 未提交事务

若存在长事务:

  • 优先联系业务方确认
  • 紧急情况下可执行:
KILL<thread_id>;

(2)检查锁等待情况
SHOWPROCESSLIST;

或:

SHOWENGINEINNODBSTATUS;

确保当前数据库没有异常锁竞争


(3)检查表结构
SHOWCREATETABLEyour_table;

确认:

  • 表是否存在主键(必须)
  • 是否已有 trigger(pt-osc 不支持)

2. 执行慢改表(标准命令)

推荐使用 pt-online-schema-change 工具。

示例命令:
pt-online-schema-change\--host=127.0.0.1\--port=3306\--user=xxx\--password=xxx\--database=your_db\--table=your_table\--alter="ADD COLUMN new_col INT DEFAULT 0"\--chunk-size=1000\--max-loadThreads_running=25\--critical-loadThreads_running=50\--sleep=0.1\--set-varsinnodb_lock_wait_timeout=50\--print\--execute

关键参数说明:

  • --alter:要执行的DDL语句
  • --chunk-size:分批拷贝的数据量(影响性能与风险)
  • --max-load:数据库负载阈值(超过自动暂停)
  • --critical-load:极限负载(超过直接终止)
  • --sleep:每批之间的休眠时间(用于降压)
  • --print:输出执行过程(建议开启)

3. 执行过程监控

在慢改表执行期间,需要持续观察系统状态:

(1)观察执行进度

pt-osc 会输出当前进度(如 10%、20%)


(2)观察数据库负载
SHOWPROCESSLIST;

关注:

  • Threads_running
  • 是否出现大量 Waiting 状态

(3)异常处理

若出现卡顿或异常:

  1. 检查是否有新产生的长事务
  2. 必要时终止异常连接
  3. 无法恢复时中断操作(Ctrl + C 或 KILL)

4. 执行完成后的确认

(1)确认数据一致性
SELECTCOUNT(*)FROMyour_table;

(2)确认业务状态
  • 接口响应时间(RT)
  • 错误率

(3)旧表处理

慢改表会保留旧表(如_old表):

DROPTABLE_old_table;

建议保留一段时间后再删除,用于回滚兜底


5. 总结

慢改表并不是“无风险操作”,其安全性依赖于:

  • 执行前的环境检查(尤其是长事务)
  • 执行中的负载控制
  • 执行后的完整验证

任何一步缺失,都可能导致线上故障。


九、总结

这次事故的本质可以归结为一句话:

在线DDL虽然避免了长时间锁表,但仍依赖 metadata lock。一旦存在未提交的长事务,会阻塞DDL获取锁,进而引发锁等待甚至死锁,最终影响业务请求。


十、可沉淀的工程经验

  1. 所有线上DDL必须有前置检查步骤
  2. 长事务是线上数据库的隐形杀手
  3. 不要相信“慢改表一定安全”
  4. 必须建立标准化 playbook 并严格执行

十一、后续优化方向

  • 建立慢改表执行 checklist(强制流程)
  • 增加长事务监控与报警
  • 自动化检测脚本(执行前校验)
  • 低峰期执行变更操作
http://www.jsqmd.com/news/576838/

相关文章:

  • 单片机与74ch595接法
  • OpenClaw可能遇到的安全风险
  • Unitree Go2 ROS2 SDK:让四足机器人像宠物一样听从你的指挥
  • YOLO12模型在计算机视觉竞赛中的实战应用
  • GLM技术复盘:篇论文深度解读智谱模型家族
  • 2026成都奔驰威霆配置可靠服务商推荐榜 - 优质品牌商家
  • 一篇讲透线程池核心代码:从 submit 到执行链路(含 lambda / move / packaged_task)
  • 告别卡顿!用z-paging虚拟列表优化Uni-app长列表,Tab切换丝滑回顶方案
  • AI CRM公司排名前瞻:原圈科技如何颠覆高净值行业获客
  • 第06章:LangChain使用之Tools
  • [实战]C语言实现带限高斯白噪声生成与Python频谱验证(附完整代码)
  • 在快马平台一键生成mac版openclaw数据抓取脚本原型
  • 为什么现代C++项目都推荐CMake+Ninja?实测构建速度对比Makefile
  • 超低功耗血压计和心率监视系统(C语言实现)
  • 树莓派入门实战:从烧录系统到远程连接全流程指南
  • 终极视频下载解决方案:如何利用Video DownloadHelper伴侣应用轻松获取在线资源
  • 避坑指南:用Python+Selenium批量爬取专利数据时,你可能遇到的5个坑及解决办法
  • 通达信手机版安装自定义指标保姆级教程:以‘双紫擒龙’为例,解决‘我的指标’不显示问题
  • SDE | 概率论基础2
  • 暗黑3终极自动化助手:5分钟配置智能战斗宏,彻底告别手酸烦恼
  • 阿里云物联网平台OTA升级避坑指南:从版本号上报到Bin文件拉取的全流程排错
  • dSPACE ControlDesk实战指南:从仪表板布局到总线信号实时监测
  • GEO和SEO有什么区别?一文看懂两代“流量入口”的分水岭
  • 零基础鸿蒙应用开发第二十二节:类的继承与多态入门
  • Monaco Editor 与 CodeMirror 深度对比:从语言支持到实际应用场景
  • A100 vs H20,谁才是DeepSeek-R1私有化的性价比之选?一份2025年的硬件选型与成本精算报告
  • 让ai成为你的命令行导师,快马平台智能解读与生成openclaw命令
  • Cesium性能优化:你可能不知道的onTick事件监听器内存泄漏问题
  • 深入解析Cache替换算法与写策略:性能优化实战指南
  • 家用除螨仪有线还是无线除螨效果好?除螨仪哪个牌子最专业?汇总揭秘除螨仪10大品牌排行