说明:标题中的MySQL 8.1在本文写作时(2023年4月)尚未发布(MySQL 8.1于2023年7月发布)。

本文基于我排查MySQL线上Bug的真实经历,分享排查过程、问题原因、解决方法,以及经验教训。

一、问题出现

1. 报警了

那天晚上,报警了。

  • 接口响应慢
  • 数据库连接数飙升
  • CPU使用率高
  • 慢查询告警
  • 我被电话叫醒了

线上问题,总是在半夜来。

2. 初步判断

初步判断:

  • 是数据库的问题
  • 不是应用的问题
  • 某个SQL特别慢
  • 导致连接堆积
  • 需要尽快找到原因

数据库,是瓶颈。

3. 开始排查

我开始排查。

  • 登录服务器
  • 看MySQL状态
  • 看慢查询日志
  • 看进程列表
  • 一步步来

排查,需要冷静。

二、排查过程

1. 第一步:看进程列表

第一步:看进程列表。

SHOW PROCESSLIST;
  • 发现很多查询在等待
  • 状态是"Sending data"
  • 有一个查询特别慢
  • 已经跑了几分钟
  • 找到了元凶

慢查询,是罪魁祸首。

2. 第二步:看慢查询日志

第二步:看慢查询日志。

# 查看慢查询配置
SHOW VARIABLES LIKE 'slow_query%';

# 查看慢查询日志
tail -f /var/log/mysql/slow.log
  • 找到了那个慢SQL
  • 是一个联表查询
  • 扫描了几百万行
  • 没有走索引
  • 问题找到了

慢查询日志,是线索。

3. 第三步:EXPLAIN分析

第三步:EXPLAIN分析。

EXPLAIN SELECT ... FROM table1 
JOIN table2 ON ... 
WHERE ...;
  • type是ALL
  • 全表扫描
  • rows是几百万
  • Extra是Using where
  • 确认没有走索引

EXPLAIN,是诊断工具。

4. 第四步:看索引

第四步:看索引。

SHOW INDEX FROM table1;
SHOW INDEX FROM table2;
  • 发现WHERE条件的字段没有索引
  • JOIN的字段也没有索引
  • 难怪慢
  • 需要加索引

索引缺失,是根本原因。

5. 第五步:为什么之前没问题

第五步:为什么之前没问题。

  • 这个SQL一直存在
  • 之前跑得好好的
  • 为什么突然慢了?
  • 看了一下数据量
  • 最近数据暴涨
  • 索引不够用了

数据增长,是导火索。

三、解决问题

1. 临时方案:Kill慢查询

临时方案:Kill慢查询。

KILL <process_id>;
  • 先把慢查询杀掉
  • 让系统恢复
  • 再慢慢优化
  • 先止血,再治病

止血,是第一步。

2. 加索引

加索引:

ALTER TABLE table1 ADD INDEX idx_field1 (field1);
ALTER TABLE table2 ADD INDEX idx_field2 (field2);
  • 给WHERE条件加索引
  • 给JOIN字段加索引
  • 加完之后
  • 查询从几秒变成几毫秒

索引,是解药。

3. 优化SQL

优化SQL:

  • 原来的SQL写得不好
  • 子查询嵌套
  • 改成JOIN
  • 只查需要的字段
  • 性能又提升了

SQL优化,是根本。

4. 验证

验证:

  • 加完索引后测试
  • EXPLAIN看执行计划
  • type变成ref
  • rows变成几十
  • 性能提升明显

验证,确保有效。

四、为什么会发生

1. 原因一:索引缺失

第一个原因:索引缺失。

  • 设计表的时候
  • 没有考虑到这个查询
  • 没有加索引
  • 数据量小的时候没问题
  • 数据量大了就慢了

索引设计,要提前考虑。

2. 原因二:数据增长

第二个原因:数据增长。

  • 业务发展快
  • 数据量暴涨
  • 原来的设计不够用了
  • 没有提前扩容
  • 没有定期优化

数据增长,是常态。

3. 原因三:没有监控

第三个原因:没有监控。

  • 没有慢查询监控
  • 没有索引使用监控
  • 问题积累到爆发才发现
  • 应该提前发现
  • 提前优化

监控,是预防。

4. 原因四:代码质量

第四个原因:代码质量。

  • SQL写得不规范
  • 没有代码审查
  • 烂SQL上线了
  • 埋下了隐患
  • 迟早出问题

代码质量,是基础。

五、经验教训

1. 教训一:索引很重要

第一个教训:索引很重要。

  • 索引是数据库性能的关键
  • 设计表的时候就要考虑
  • 定期检查索引使用情况
  • 删除无用索引
  • 添加缺失索引

索引,是数据库的生命线。

2. 教训二:监控要完善

第二个教训:监控要完善。

  • 慢查询监控
  • 连接数监控
  • CPU监控
  • 磁盘监控
  • 告警要及时

监控,是眼睛。

3. 教训三:定期优化

第三个教训:定期优化。

  • 定期检查慢查询
  • 定期优化SQL
  • 定期整理索引
  • 定期归档数据
  • 不要等出问题才优化

定期优化,是习惯。

4. 教训四:代码审查

第四个教训:代码审查。

  • SQL也要审查
  • 看执行计划
  • 看索引使用
  • 烂SQL不要上线
  • 从源头避免问题

代码审查,是防线。

5. 教训五:备份和回滚

第五个教训:备份和回滚。

  • 操作前备份
  • 加索引前测试
  • 有回滚方案
  • 出问题能快速恢复
  • 不要裸操作

备份,是最后的保障。

六、排查技巧

1. 技巧一:保持冷静

第一个技巧:保持冷静。

  • 线上问题不要慌
  • 慌了容易出错
  • 一步步来
  • 先止血再优化
  • 冷静才能解决问题

冷静,是最重要的素质。

2. 技巧二:先看状态

第二个技巧:先看状态。

  • SHOW PROCESSLIST
  • SHOW STATUS
  • 看整体状态
  • 再定位具体问题
  • 不要一上来就改

先看状态,再动手。

3. 技巧三:用对工具

第三个技巧:用对工具。

  • EXPLAIN
  • 慢查询日志
  • performance_schema
  • 监控系统
  • 工具能帮你快速定位

工具,是效率的倍增器。

4. 技巧四:记录过程

第四个技巧:记录过程。

  • 排查的时候记录
  • 做了什么
  • 结果是什么
  • 方便事后复盘
  • 方便团队分享

记录,是成长的开始。

5. 技巧五:事后复盘

第五个技巧:事后复盘。

  • 问题解决后复盘
  • 根因是什么
  • 怎么避免
  • 流程怎么改进
  • 不要白踩坑

复盘,是进步的阶梯。

七、预防措施

1. 措施一:建立慢查询告警

第一个措施:建立慢查询告警。

  • 超过1秒的SQL告警
  • 及时发现
  • 及时优化
  • 不要等堆积

告警,是预警。

2. 措施二:定期索引审计

第二个措施:定期索引审计。

  • 每月检查索引
  • 删除无用索引
  • 添加缺失索引
  • 优化索引结构

审计,是维护。

3. 措施三:SQL上线审查

第三个措施:SQL上线审查。

  • 新SQL必须审查
  • 看执行计划
  • 看索引使用
  • 烂SQL不上线

审查,是把关。

4. 措施四:数据归档

第四个措施:数据归档。

  • 历史数据归档
  • 保持表数据量合理
  • 分区表
  • 冷热分离

归档,是减负。

5. 措施五:压测

第五个措施:压测。

  • 上线前压测
  • 模拟大流量
  • 发现性能瓶颈
  • 提前优化

压测,是保险。

八、写在最后

线上出了个MySQL的Bug,我排查了一夜。

问题是索引缺失导致的慢查询,数据增长后爆发。排查过程:看进程列表、看慢查询日志、EXPLAIN分析、看索引、找到原因。解决方法:Kill慢查询止血、加索引、优化SQL、验证。经验教训:索引很重要、监控要完善、定期优化、代码审查、备份和回滚。

2023年了,数据库依然是系统的核心,也是最容易出问题的地方。线上问题不可怕,可怕的是不从问题中学习。每次排查,都是一次成长。建立完善的监控和流程,才能减少问题的发生。

最后,用一句话总结:"线上Bug不可怕,可怕的是不总结。每次排查都是一次学习,建立流程,预防为主,才能少熬夜。"

愿你少遇到线上Bug,遇到了也能从容应对。