备份做得多了,磁盘就吃不消了。不少DBA都遇到过这样的情况:某天早上收到磁盘告警,登录服务器一看,/data/backup目录下堆了几百GB的mysqldump文件,最早的甚至可以追溯到半年前,而这些备份绝大部分早已失去了保留价值。备份的意义在于出问题时能够恢复,而不是无限期囤积。本文就来聊聊如何科学地清理MySQL过期备份,把空间维护做成一件自动化、可放心托付的事。

先制定备份保留策略,再谈清理
清理之前必须先回答一个问题:多久的备份算过期?这没有统一答案,取决于业务的数据变更频率和恢复容忍度。一个常见的做法是分层保留,比如最近7天的每日全量备份保留,7天到30天之间每周保留一份,30天到180天之间每月保留一份,180天以前的全部删除。这种策略既保证了近期可以快速恢复到任意一天,又能把长期备份的空间占用压缩到很低。
确定了策略,接下来是命名规范。清理脚本要能准确识别哪些文件该删,前提是备份文件名里带上了清晰的时间戳。推荐使用YYYYmmdd或者YYYY-mm-dd_HHMMSS这样的格式,例如mydb_full_20240315.sql.gz,一眼就能看出备份日期,脚本解析起来也简单。
另外还要区分全量备份和增量备份。全量备份体积大但恢复简单,增量备份体积小但依赖基础全量。清理增量备份时要格外小心,如果它依赖的全量备份被删了,那这个增量就成了废数据,可以一并清理。
用find命令按时间批量删除过期备份
Linux下清理过期文件最直接的工具就是find命令。假设我们的备份目录是/data/mysql_backup,要删除30天以前的压缩备份文件,可以这样写:
# 删除30天前修改的备份文件,先预览确认
find /data/mysql_backup -name "*.sql.gz" -mtime +30 -ls
# 确认无误后执行删除
find /data/mysql_backup -name "*.sql.gz" -mtime +30 -exec rm -f {} \;这里要注意-mtime +30的含义:文件修改时间在31天及以上才会匹配,也就是说+30实际是保留最近31天。如果希望精确保留30天,应该用-mtime +29。这个差一问题在实际工作中坑过不少人,建议先用-ls参数预览要删除的文件列表,确认没有误伤再执行删除。
如果想按分钟或者小时控制得更精细,可以用-mmin参数。比如删除7天以前的文件:
# 按分钟数删除,7天等于10080分钟 find /data/mysql_backup -name "*.sql.gz" -mmin +10080 -delete
-delete比-exec rm执行效率更高,但风险也更高,因为它没有确认过程。生产环境建议优先使用-exec rm -f {} \;的方式,配合日志记录。同时要特别注意,不要在根目录或者错误的路径下执行find删除命令,路径写错一个字符,后果可能无法挽回。
编写自动化清理脚本并配合crontab定时执行
手动清理终究不是长久之计,把清理逻辑固化成脚本,交给crontab定时跑,才是正解。下面是一个兼顾了清理和日志记录的脚本示例:
#!/bin/bash
# mysql备份自动清理脚本
BACKUP_DIR="/data/mysql_backup"
KEEP_DAYS=30
LOG_FILE="/var/log/mysql_backup_clean.log"
echo "==== $(date '+%F %T') 开始清理 ====" >> $LOG_FILE
# 统计清理前空间
BEFORE=$(du -sh $BACKUP_DIR | awk '{print $1}')
# 删除过期备份并记录日志
find $BACKUP_DIR -name "*.sql.gz" -mtime +$KEEP_DAYS -print -exec rm -f {} \; >> $LOG_FILE 2>&1
# 统计清理后空间
AFTER=$(du -sh $BACKUP_DIR | awk '{print $1}')
echo "清理前空间: $BEFORE, 清理后空间: $AFTER" >> $LOG_FILE这个脚本做了三件事:删除过期文件、把删除的文件名写入日志、记录清理前后的空间变化。日志非常重要,一旦发现误删,至少还能追溯当时删了哪些文件。
然后配置crontab,让脚本每天凌晨四点执行:
# crontab -e 添加以下内容 0 4 * * * /opt/scripts/clean_mysql_backup.sh
选择凌晨四点是因为很多备份任务安排在凌晨一到三点,清理任务放在备份完成之后,能保证当天的备份不会刚生成就被删掉。如果备份任务结束时间不确定,可以在清理脚本里加一个保护逻辑,跳过24小时内生成的文件,也就是上面-mtime +30天然就满足的条件,只要KEEP_DAYS设置合理就不会误删新备份。
清理过程中的常见坑与注意事项
第一是误删风险。清理脚本上线前,务必在测试环境跑一遍,或者先只保留-ls预览逻辑观察一周再开启真实删除。有些团队还会在脚本里加一道保险,比如当天的日期变量为空时不执行删除,防止find在异常情况下匹配到不该删的文件。
第二是binlog的清理。很多备份方案会配合binlog做基于时间点的恢复,直接用rm删除binlog文件是危险操作,正确的方式是使用SQL语句:
-- 清理7天前的binlog PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 7 DAY);
或者在配置文件中设置expire_logs_days(MySQL 8.0及以上版本为binlog_expire_logs_seconds),让MySQL自动清理过期的binlog,避免手工删除导致的主从复制异常。
第三是权限问题。执行删除的用户必须对备份目录有写权限,同时crontab运行环境与交互shell不同,脚本里的路径最好全部写成绝对路径,环境变量的加载也要显式处理,否则手动执行正常、定时任务失败的情况会反复出现。最后,清理策略要定期复盘,业务量增长后备份体积可能翻倍,原来的保留天数可能需要动态调整,空间监控告警配合自动化清理,才能让备份体系长期健康运转。