返回首页

MySQL 磁盘告警飙到 92%?两条 SQL,5分钟定位根因

MySQL 磁盘告警飙到 92%?两条 SQL,5分钟定位根因

大家好,我是老张。

做运维最怕什么告警?磁盘使用率。特别是数据库的磁盘告警——处理慢了业务要停,处理快了怕删错数据。上周就遇到一个典型的案例:Meta 库的 MySQL 磁盘飙到 92%,再不处理就要炸。


📊 告警来了

上午10 点,告警钉过来:

规则:Mysql Pod 磁盘使用率(数据+日志总量) 阈值:> 80% 当前值:92.19% 节点:备节点

一个 80GB 本地 SSD 的 MySQL 8.0 主备实例,磁盘吃到了 92%。先上控制台看一眼。


🔍 第一层:控制台快速确认

控制台看到的磁盘明细:

节点数据Binlog其他日志使用率
主节点71.41 GB455 MB108 MB89.95%
备节点73.36 GB500 MB3.5 MB92.33%

一眼就看出问题:Binlog 才 500MB,不是 binlog 堆积导致的。

为什么这么判断?因为 Binlog 清理策略设的是:本地保留 6 小时,最大占用 30%(即 24GB),剩余 < 5GB 或总使用率 > 80% 自动清理。策略正常生效,binlog 很干净。

那就只能是数据本身在涨。 进库看看。


🔬 第二层:按库定位

连上 MySQL,先按库统计大小:

SELECT table_schema AS '数据库',
       ROUND(SUM(data_length + index_length) / 1024 / 1024 / 1024, 2) AS '大小(GB)'
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys')
GROUP BY table_schema
ORDER BY 2 DESC;

结果:

数据库大小占比
billing_db(计量计费库)48.69 GB77%
service_a6.78 GB11%
service_b4.90 GB8%
其余 97 个库~3 GB4%

billing_db 一个库吃掉 77% 的空间。 范围缩得很快。


🎯 第三层:大表定位

继续往深挖,看 billing_db 内部到底哪些表最大:

SELECT table_name,
       ROUND((data_length + index_length) / 1024 / 1024 / 1024, 2) AS '大小(GB)',
       table_rows, engine
FROM information_schema.tables
WHERE table_schema = 'billing_db'
ORDER BY data_length + index_length DESC
LIMIT 10;

Top 10 大表:

大小行数说明
t_bill_detail11.20 GB622万账单明细
t_charge_record8.03 GB425万计费记录
t_measure_std3.99 GB459万标准计量
t_measure_base3.10 GB336万基础计量
t_settle_detail2.75 GB433万结算任务
t_idempotent2.69 GB1049万幂等表
t_measure_raw2.52 GB350万原始计量
t_instance_msg2.51 GB23万计量实例信息
t_charge_job1.62 GB368万计费任务
t_producer_msg1.49 GB30万出账实例信息

全部是计量计费相关表。特别注意到 t_instance_msg 只有 23 万行却占了 2.51GB,查下表结构:

SHOW CREATE TABLE billing_db.t_instance_msg\G

发现三个 longtext 字段(instance_dataorder_listmeasure_list),存的都是序列化 JSON,单行平均 11KB。业务设计如此,不能砍。


💡 根因确认

定位很清晰:

  • 根因billing_db 计量计费库独占 48.69 GB(77%),80GB 磁盘容量不足
  • 定性:不是异常,是业务数据正常累积。计费系统数据只增不减
  • Binlog:~500MB,清理策略正常,排除干扰项

至此,排查只花了不到 5 分钟,SQL 也就两三条。


🔧 处理方案

思路

两条路:

  1. 扩容磁盘:80GB → 200GB,一劳永逸
  2. 清理数据:如果业务还没正式启用,可以直接清空

实际的情况是计费功能尚未启用,所以可以直接清理,不用扩容。

执行

跟业务确认后,truncate 掉最大的三张表:

USE billing_db;
TRUNCATE TABLE t_bill_detail;    -- 释放 11.20 GB
TRUNCATE TABLE t_charge_record;  -- 释放 8.03 GB
TRUNCATE TABLE t_measure_std;    -- 释放 3.99 GB

📈 清理效果

指标清理前清理后
磁盘使用率92%61%
主节点数据71.41 GB47.72 GB
备节点数据73.36 GB49.38 GB
释放空间~24 GB

三张表,回收 24GB,磁盘从 92% 降到 61%,告警消除。


🧠 老张的几点总结

1. 排查要有"排除法"思维

看到磁盘告警,不要上来就清 binlog、清日志。先看一眼 binlog 到底多大,确认是不是它的问题。这次如果一上来就调 binlog 保留策略,等于瞎忙活。

排查路径:控制台确认总量 → 排除 binlog → 库级统计 → 大表定位 → 表结构确认。每一层都在缩小范围。

2. information_schema.tables 是排查利器

两条 SQL 定位问题:

-- 按库统计
SELECT table_schema, ROUND(SUM(data_length + index_length)/1024/1024/1024, 2) AS 'GB'
FROM information_schema.tables GROUP BY table_schema ORDER BY 2 DESC;

-- 库内大表
SELECT table_name, ROUND((data_length + index_length)/1024/1024/1024, 2) AS 'GB', table_rows
FROM information_schema.tables WHERE table_schema='xxx' ORDER BY data_length + index_length DESC;

记住这两条,磁盘排查基本够用。

3. 计量/计费类库要有归档策略

计量数据天然只增不减。80GB 磁盘跑计量库,迟早会满。这类库从一开始就应该:

  • 定好数据保留周期(比如只保留最近 3 个月)
  • 配置定期归档任务
  • 或者直接给够磁盘空间(200GB 起步)

📋 排查清单(建议收藏)

下次遇到 MySQL 磁盘告警,按这个顺序走:

  1. ☐ 控制台确认磁盘使用明细(数据 vs binlog vs 日志)
  2. ☐ 确认 binlog 清理策略是否正常
  3. ☐ 进库按库统计大小
  4. ☐ 定位大表
  5. ☐ 确认大表表结构(是否有 longtext/json 大字段)
  6. ☐ 判断是否业务正常增长 or 异常
  7. ☐ 扩容 or 清理,选一条路

💬 互动话题

  1. 你遇到过最头疼的 MySQL 磁盘告警是什么样的?

欢迎在评论区聊聊,老张等着你 👇

A

Admin

用文字记录生活与思考。

评论 (0)
暂无评论,来抢沙发吧
MySQL 磁盘告警飙到 92%?两条 SQL,5分钟定位根因 | 山外云的Vlog