【数据库实战】RDS磁盘告警但数据不多?InnoDB碎片回收与无锁重建的工程解法
许多开发者在收到 RDS 磁盘满告警时,第一时间写了批处理脚本去 DELETE 千万级别的历史日志数据。但诡异的是,删除跑完后,df -h 查看底层磁盘空间居然一 MB 都没有释放。
这是因为 MySQL InnoDB 引擎的底层 B+ 树特性。执行 DELETE 只是将数据页标记为“可复用(Deleted)”,并没有将物理空间真正还给操作系统,这些未被释放的空洞被称为“表空间碎片(Fragmentation)”。
标准的工程排障解法是:精准定位碎片率极高的“毒瘤表”,并利用在线 DDL 技术重新整理底层物理页。
1. 极速扫描全库碎片率
不要盲目排查,直接连入 RDS,利用 information_schema.tables 字典表,揪出那些 DATA_FREE(碎片空洞)占据绝对物理空间的大表:
-- 查询全库各表的物理大小与碎片闲置空间,按碎片量倒序排列
SELECT
table_schema AS '数据库',
table_name AS '表名',
ROUND(data_length / 1024 / 1024, 2) AS '实际数据大小(MB)',
ROUND(data_free / 1024 / 1024, 2) AS '碎片空洞大小(MB)',
ROUND((data_free / (data_length + data_free)) * 100, 2) AS '碎片率(%)'
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')
AND data_free > 0
ORDER BY data_free DESC
LIMIT 10;
2. 在线无锁重建表空间(Online DDL)
定位到碎片率极高(如超过 30% 且体积达数十 GB)的表后,绝不能在业务高峰期直接执行原生的 OPTIMIZE TABLE,因为老版本 MySQL 会对全表加读写锁。 对于 MySQL 5.6 及以上版本,必须使用基于 INPLACE 算法的伪装 ALTER 命令,在不阻塞线上并发读写的情况下,让 InnoDB 在底层默默重建一个排列紧密的新 .ibd 文件并替换旧文件:
-- 💡 核心:指定 ALGORITHM=INPLACE 和 LOCK=NONE
-- 强令 MySQL 在重建 B+ 树物理结构时不阻塞当前线上的 DML(增删改)操作
ALTER TABLE business_logs ENGINE=InnoDB, ALGORITHM=INPLACE, LOCK=NONE;
3. 定期维保自动化脚本
碎片整理会消耗大量 CPU 与 I/O 资源,千万不要让其在白天触发。应将其沉淀为 DBA 自动化运维脚本,结合 Cronjob 在凌晨 3 点业务低谷期执行。如果表体积达到百 GB 级别,建议直接使用开源工具 gh-ost 或 pt-online-schema-change 以确保绝对的平滑。
总结: 云端数据库存储成本高昂,决不能让无用的“物理碎片”白白消耗预算。通过底层字典表的精准监控与无锁 ALTER 技术的配合,开发者可以在对前端业务彻底无感的情况下,完成数据库底盘的大扫除,是延长 RDS 实例生命周期的必备技能。
- 点赞
- 收藏
- 关注作者
评论(0)