mysql日志表满了无法删除
凌晨两点,志表手机开始疯狂弹告警。满无我眯着眼看了一眼——磁盘使用率98%。法删不用猜,志表肯定是满无那台跑了三年多的MySQL服务器出事了。登上机器一查,法删/var/lib/mysql下面一个叫mysql-bin.000487的志表日志文件,占了整整42个G。满无
这就是法删典型的MySQL日志表满了。但麻烦的志表地方在于,你直接rm掉它,满无MySQL根本不认账。法删它还会拿着那个文件句柄继续写,志表磁盘空间不会释放。满无我第一次遇到这情况的法删时候也傻,删完文件一看,df -h纹丝不动,差点以为见了鬼。
先搞清楚是哪种日志在吃磁盘
MySQL的日志有好几种,搞错了对象等于白忙活。binlog是二进制日志,主从复制和恢复都靠它,通常也是占空间最狠的。error log一般不大,但如果错误刷屏也能撑爆磁盘。slow query log要看你的long_query_time设了多少,设成0的话,所有查询都往里灌,几天就能吃掉几十个G。还有relay log、general log,各有各的坑。
我那台机器的情况是binlog没设过期时间。expire_logs_days默认值是0,意思是永不删除。三年前搭环境的时候没在意,结果日积月累,硬生生把磁盘塞满了。
删不掉的真正原因
很多人第一反应是DELETE FROM mysql.general_log或者直接删文件。前者对general log可能有用,但binlog根本不在表里,你删不到。后者的问题是Linux的文件系统机制——进程打开的文件,即使你删了目录项,inode还在被占用,空间不会回收。
正确的做法是用MySQL自己的命令来清理:
PURGE BINARY LOGS BEFORE '2024-01-01 00:00:00'; 或者按文件名:
PURGE BINARY LOGS TO 'mysql-bin.000450'; 执行完这个,MySQL会自己关闭并删除对应的文件句柄,磁盘空间立刻释放。我当时跑完第一条命令,df -h从98%掉到31%,那种感觉比修好任何bug都爽。
临时救急和长期方案
如果磁盘已经100%了,MySQL连PURGE命令都执行不了怎么办?有个笨办法但管用:先停掉MySQL,手动删掉旧的binlog文件,然后修改my.cnf,加上expire_logs_days=7,再启动。注意手动删的时候要保留mysql-bin.index里记录的最新几个文件,否则启动会报错。
长期来看,光设过期时间还不够。我后来加了个cron任务,每天凌晨跑一次PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY),双保险。另外把max_binlog_size从默认的1G调成了256M,单个文件小一点,清理起来更灵活。
还有一点容易被忽略:如果你用了主从复制,从库的relay log也会堆积。relay_log_purge默认是ON,但有些老版本或者特殊配置下会失效。检查一下SHOW VARIABLES LIKE 'relay_log_purge',确保它是ON。
一个真实的翻车案例
去年帮朋友处理过一台阿里云RDS。他图省事,直接在控制台点了“删除日志”,结果把还在用的binlog删了,主从直接断掉。RDS的日志清理有它自己的逻辑,不能乱动。后来花了两个小时重建从库,被老板骂得够呛。云数据库的日志管理界面看着简单,但每个按钮背后是什么行为,最好先看文档。
自建MySQL的话,控制权在你手里,但也意味着责任在你手里。expire_logs_days这个参数在MySQL 8.0里已经标记为废弃,要用binlog_expire_logs_seconds代替。默认值2592000秒,也就是30天。如果你从5.7升级到8.0,记得检查这个参数,不然行为可能跟你想的不一样。
说到底,日志表满了不是技术难题,是个管理问题。搭环境的时候多写一行配置,比出事之后熬夜删文件强得多。我现在每台新装的MySQL,第一件事就是设日志过期时间,第二件事是加磁盘监控。这两条规矩,帮我省了至少三个不眠之夜。









