MySQL的二进制日志(binary log,常配置为log-bin)记录了所有修改数据的语句,是主从复制和按时间点恢复的基础。随着业务写入量增加,这些日志会持续堆积,若不加以管理,很容易把数据盘写满,导致实例拒绝写入甚至宕机。很多人在发现磁盘告警时第一反应是去操作系统层面直接删除文件,这种做法非常危险,因为MySQL内部仍记录着这些日志的索引,直接rm会造成元数据不一致,复制可能中断且无法重启。正确的清理必须借助MySQL自身的机制来完成。

一、理解二进制日志与删除风险
二进制日志并不是普通的无用日志,它包含形如mysql-bin.000001、mysql-bin.000002的文件以及索引文件mysql-bin.index。主库将日志发送给从库,从库通过IO线程读取并落盘,再由SQL线程回放。如果主库删除了从库尚未读取的日志,从库就会报1236错误,复制直接断掉,只能重新搭建或者跳过事务,成本很高。
因此删除前必须明确两个位点:主库当前正在写入的是哪个文件,以及从库已经执行到哪个文件。只有在从库安全位点之后的日志,才允许在主库清理。另外,若开启了基于时间点的备份恢复方案,被清理的日志对应的时间段将无法恢复,需要结合全量备份周期来定保留天数。
二、查看日志状态与从库位点
登录MySQL后,先用以下命令查看主库二进制日志列表和当前状态:
-- 查看所有二进制日志文件及大小 SHOW BINARY LOGS; -- 查看当前正在写入的日志文件及位点 SHOW MASTER STATUS;
在从库上执行下列命令,确认复制进度:
-- 查看从库读取和执行到的主库日志位点 SHOW SLAVE STATUSG -- 重点关注这两行: -- Relay_Master_Log_File: mysql-bin.000010 -- Exec_Master_Log_Pos: 154
通过上述输出,若主库SHOW BINARY LOGS中mysql-bin.000009及之前的文件都小于从库的Relay_Master_Log_File,说明从库已经处理完这些日志,主库可以放心清理它们。若使用GTID模式,则应当关注Retrieved_Gtid_Set与Executed_Gtid_Set,确保待删日志对应的GTID都已执行。
三、使用PURGE命令手动清理
MySQL提供了PURGE BINARY LOGS语句,分为按文件名和按时间两种写法。按文件名删除会清除指定文件之前的所有日志:
-- 删除 mysql-bin.000010 之前的所有日志(不含000010) PURGE BINARY LOGS TO 'mysql-bin.000010'; -- 删除2023-01-01 00:00:00之前的日志 PURGE BINARY LOGS BEFORE '2023-01-01 00:00:00';
这种方式的优点是精准、可控,适合在磁盘即将写满的紧急场景下,由运维人员评估后立刻释放空间。执行后MySQL会自动更新索引文件,不需要重启。需要注意的是,BEFORE后面跟的是本地时间,且删除操作本身也会记录进二进制日志(除非会话禁写),从库收到后也会同步清理自己的中继日志引用。
手动清理的缺点在于必须人工介入,若没有监控告警就容易遗忘。在生产中建议仅将其作为应急手段,日常依靠自动过期策略来维护。同时,执行PURGE时若指定的文件名比当前正在写入的还新,命令会报错,不会误删活动日志,这一点设计上比较安全。
四、配置自动过期避免堆积
从MySQL 5.7开始,推荐使用binlog_expire_logs_seconds参数(早期版本为expire_logs_days)来控制日志保留时长。设置后,MySQL会在日志切换时自动删除超过期限的旧文件:
-- 设置保留7天(604800秒) SET GLOBAL binlog_expire_logs_seconds = 604800; -- 写入配置文件 my.cnf 永久生效 -- [mysqld] -- binlog_expire_logs_seconds = 604800
自动过期机制由MySQL的后台线程驱动,在每次日志轮转或启动时检查,不需要外部脚本。它基于文件修改时间计算,因此即使写入量很低,只要超过设定周期也会被清掉。与手动PURGE相比,自动策略能防止人为疏忽,但无法应对突发的、保留周期内就写满磁盘的极端写入高峰,所以两者常结合使用。
如果实例是纯单机且不需要时间点恢复,也可以直接将expire设得很短,比如半小时,但这会牺牲恢复能力。对于一主多从架构,主库过期时间应大于从库延迟可能的最大值,否则从库延迟高时会丢失未读取的日志。
五、清理后的空间验证与监控
执行删除后,可通过操作系统命令或SQL再次确认空间变化:
# 查看日志目录占用 du -sh /var/lib/mysql/mysql-bin* # 查看磁盘整体使用 df -h /var/lib/mysql
同时建议在监控系统中对二进制日志目录单独设告警,例如当单个binlog超过2G或目录总大小超过数据文件20%时通知。另外,定期用SHOW BINARY LOGS比对增长速率,能提前发现异常大事务导致的日志暴涨。清理动作完成后,务必观察主从状态是否仍为Yes,避免清理过程中因位点误判引发复制异常。
| 清理方式 | 适用场景 | 优点 | 风险点 |
|---|---|---|---|
| PURGE手动 | 磁盘紧急告警 | 即时释放,精准控制 | 依赖人工判断位点 |
| 自动过期 | 日常运维 | 无需干预,防堆积 | 无法应对极端写满 |
六、常见误区与总结
一个典型误区是认为用rm删掉文件再重启MySQL就能解决,实际上索引文件未更新会导致启动失败或复制错乱。另一个误区是在从库上执行PURGE,从库一般不产生binlog(除非log_slave_updates开启),清理主库日志必须从主库发起。正确做法是结合SHOW命令确认位点,优先配置自动过期,紧急时用PURGE按文件清理,并始终保留从库已消费之后的日志。这样既能释放磁盘,又能保障复制与恢复能力不受影响。