find -mtime +N 删除错误是因为 -mtime 基于距今完整24小时而非创建日,且 mtime 易被 touch 或 rsync 误改;应统一用 touch -d "$DATE" 对齐时间戳,或按文件名匹配清理。
find -mtime +N 清理为什么有时删错文件?
因为 -mtime 看的是“距今多少个完整 24 小时”,不是“创建日期超过 n 天”。比如一个文件是昨天 23:59 创建的,今天 00:01 运行 find -mtime +0,它不会被匹配——因为还没满 24 小时。
- 实际保留逻辑应按“最后修改时间”计算,而备份脚本中
mysqldump | gzip生成的.sql.gz文件,其mtime就是压缩完成时刻,一般可靠 - 但若备份后又用
touch或 rsync 同步过,mtime可能被意外更新,导致误删;此时应改用-printf '%T@ %p\n' | awk按精确秒级时间过滤 - 更稳妥的做法:统一在备份脚本末尾加
touch -d "$DATE" "$BACKUP_FILE",让文件时间戳对齐命名中的日期,后续清理可直接按名匹配(如find ... -name 'mydb_202[0-9][0-9][0-9][0-9]_*.sql.gz')
保留最新 N 个备份比按天数更安全吗?
不一定。按数量保留(如只留最近 5 个)在备份失败或漏跑时会掩盖问题——比如连续 3 天没成功备份,你仍剩 5 个“旧”文件,但实际已无有效新备份;而按天数(如 RETENTION_DAYS=7)能暴露中断,日志里会显示“未找到可删文件”,反而提醒你检查失败原因。
- 生产环境推荐“分层保留”:关键库(如用户账户库)用
RETENTION_DAYS=90,普通业务库用30,临时测试库用7 - 若必须按数量,别直接
ls | head -n -5,要用find -printf '%T@ %p\n' | sort -n | head -n -5 | cut -d' ' -f2- | xargs rm -f,避免文件名含空格或换行时报错 - 注意:MySQL 的
mysqldump --single-transaction备份本身不保证跨实例一致性,若主从延迟大,单纯保留多个备份不能替代 GTID 或 binlog 位点定位
清理脚本加了 -delete 却没反应?常见权限与路径陷阱
find ... -delete 要求对**父目录有写权限**,不是对文件本身。也就是说,即使你能 rm 某个 .sql.gz,但若 /data/backups 目录属主是 root、权限是 755,而清理脚本以 mysql 用户运行,-delete 就会静默失败。
- 先验证权限:
ls -ld $BACKUP_DIR,确保运行脚本的用户对该目录有w权限 - 别用通配符路径如
/data/backup/*,find不展开 shell 通配,应写死BACKUP_DIR="/data/backup/mysql" - 上线前务必在测试机跑一次带
-print的预演命令:find "$BACKUP_DIR" -name "*.sql.gz" -type f -mtime +7 -print,确认列出的全是预期文件 - 严禁在脚本里写
rm -rf $BACKUP_DIR/*类操作——路径变量为空时会变成rm -rf /*,真发生过
跨版本恢复时,旧备份真的能用吗?
不能默认认为“能备份就能恢复”。MySQL 5.7 备份的 .sql 在 8.0 上可能因 utf8mb3→utf8mb4 默认变更、NO_AUTO_CREATE_USER 移除等报错;PostgreSQL 12 的 pg_dump 输出在 15 上恢复也可能因权限模型调整失败。
- 每次数据库升级前,必须用旧备份在同版本测试库执行一次完整恢复流程,并校验表行数和关键字段值
- 备份脚本里加上版本标识:
echo "# MYSQL_VERSION: $(mysql --version)" > "$BACKUP_FILE",追加到压缩包开头,方便后续排查 - 不要只存
.sql.gz,对核心库额外存一份mysqldump --tab生成的纯数据文件(.txt),它格式稳定、跨版本兼容性更好,只是恢复慢一点
最常被跳过的一步:清理策略生效前,没验证过恢复链是否完整。删掉的不是文件,是某次 RPO 时间点的唯一凭证。










