在MySQL数据库系统中,binlog(二进制日志)是记录所有修改数据的SQL语句(以及可能的数据变更)的重要日志文件。它不仅是主从复制的核心组件,也是数据恢复的关键依据。但随着时间的推移,这些日志文件会不断累积,占用大量磁盘空间。
binlog文件通常位于MySQL数据目录下(可通过show variables like 'datadir'查看),文件名格式为mysql-bin.000001这样的序列。每个事务提交后,相关变更都会被记录到当前活跃的binlog文件中。当文件达到max_binlog_size设定值(默认1GB)时,MySQL会自动创建新文件。
重要提示:直接删除binlog文件可能导致数据恢复失败和复制中断,必须采用MySQL提供的安全机制进行操作。
这是MySQL官方推荐的标准方法,语法如下:
sql复制PURGE BINARY LOGS TO 'mysql-bin.000010'; -- 删除指定文件之前的所有日志
PURGE BINARY LOGS BEFORE '2023-01-01 00:00:00'; -- 删除指定时间前的日志
实际操作案例:
sql复制-- 首先查看现有binlog文件列表
SHOW BINARY LOGS;
/*
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000023 | 104857600|
| mysql-bin.000024 | 104857600|
| mysql-bin.000025 | 52428800|
+------------------+-----------+
*/
-- 保留最近两个文件,删除更早的日志
PURGE BINARY LOGS TO 'mysql-bin.000025';
-- 验证删除结果
SHOW BINARY LOGS;
/*
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000024 | 104857600|
| mysql-bin.000025 | 52428800|
+------------------+-----------+
*/
在my.cnf配置文件中添加(或修改):
ini复制[mysqld]
expire_logs_days = 7 # 自动保留最近7天的日志
动态修改(无需重启):
sql复制SET GLOBAL expire_logs_days = 7;
这个方案的优势是自动化管理,但需要注意:
FLUSH LOGS命令对于需要更精细控制的场景,可以使用官方工具包中的专用工具:
bash复制mysqlbinlogpurge --master=root:password@localhost --slaves=root:password@slave1
该工具会:
执行删除操作前必须确认:
主从复制状态:
sql复制SHOW SLAVE STATUS\G
确保Relay_Master_Log_File显示的日志文件早于待删除的文件
备份状态:
sql复制SHOW VARIABLES LIKE 'log_bin%';
确认没有活跃的备份进程依赖旧日志
磁盘空间监控:
bash复制df -h /var/lib/mysql
du -sh /var/lib/mysql/mysql-bin.*
问题1:执行PURGE命令后空间未释放
bash复制lsof | grep mysql-bin | grep deleted
kill -9 <PID> # 谨慎操作
问题2:从库复制中断报错"Could not find first log file"
sql复制STOP SLAVE;
CHANGE MASTER TO MASTER_LOG_FILE='当前最早的文件名', MASTER_LOG_POS=4;
START SLAVE;
问题3:expire_logs_days不生效
sql复制SHOW VARIABLES LIKE 'expire_logs_days';
sql复制FLUSH LOGS;
结合crontab的自动维护方案:
bash复制#!/bin/bash
# 保留最近3天日志,每天凌晨执行
MYSQL_USER="root"
MYSQL_PASS="yourpassword"
KEEP_DAYS=3
DATE=$(date -d "$KEEP_DAYS days ago" +"%Y-%m-%d %H:%M:%S")
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "PURGE BINARY LOGS BEFORE '$DATE';"
| 参数名 | 默认值 | 建议值 | 作用 |
|---|---|---|---|
| max_binlog_size | 1G | 1-2G | 单个日志文件最大尺寸 |
| binlog_expire_logs_seconds | 0 | 604800 | 7天保留时间(与expire_logs_days二选一) |
| binlog_format | ROW | ROW | 推荐使用ROW格式减少日志量 |
| binlog_row_image | FULL | MINIMAL | 只记录变更的最小数据集 |
对于特别大的binlog文件,可以先压缩归档再删除:
bash复制# 导出日志内容并压缩
mysqlbinlog /var/lib/mysql/mysql-bin.000123 | gzip > binlog-000123.sql.gz
# 验证导出完整性
zgrep "# at " binlog-000123.sql.gz | tail -n 1
建议部署以下监控项:
日志增长速率监控:
sql复制SHOW BINARY LOGS;
定期记录File_size变化
复制延迟告警:
sql复制SHOW SLAVE STATUS\G
监控Seconds_Behind_Master
磁盘空间预测:
bash复制# 预测7天后日志量
awk '{sum+=$2} END {print sum*7/1024/1024 " GB"}' <(mysql -e "SHOW BINARY LOGS" -ss)
当磁盘使用率超过90%时:
sql复制SET GLOBAL max_binlog_size=1073741824; -- 临时调小单个文件大小
FLUSH LOGS; -- 立即创建新文件
PURGE BINARY LOGS BEFORE NOW(); -- 删除所有非活跃日志
计划内切换:
sql复制STOP SLAVE;
RESET MASTER; -- 清空所有binlog
计划外切换:
sql复制SET GLOBAL expire_logs_days=0; -- 临时禁用自动清理
当启用GTID模式时:
删除日志前必须确保:
sql复制SELECT @@global.gtid_purged;
该值包含所有待删除日志中的GTID
安全删除步骤:
sql复制SHOW SLAVE STATUS\G
确保Retrieved_Gtid_Set包含所有GTIDsql复制PURGE BINARY LOGS BEFORE '2023-01-01';
经过多年运维经验,我总结出以下黄金准则:
容量规划三原则:
删除操作四步法:
配置优化建议:
ini复制[mysqld]
expire_logs_days = 14
max_binlog_size = 1G
binlog_format = ROW
binlog_row_image = MINIMAL
sync_binlog = 1 # 重要生产环境建议
灾难恢复预案:
最后分享一个真实案例:某电商平台在618大促期间因未及时清理binlog导致磁盘写满,整个数据库集群不可用。事后我们建立了自动化监控体系,当日志总量超过磁盘50%时自动触发告警,并开发了分级清理策略——业务低峰期保留7天日志,大促期间延长至30天。这个方案在后续的双11活动中成功预防了类似事故。