配置定时备份数据库之前,我会先确认现象,而不是直接编辑 crontab。备份失败的原因往往不是 cron 表达式写错,而是命令本身在定时任务里跑不起来。所以先确认 crontab 是否可用,再确认 mysqldump 的实际路径。
配置备份任务前,先确认系统 crontab 是否可用。执行 crontab -l 查看当前用户已有任务,如果命令不存在或提示无权限,需要安装 cron 服务并确保服务已启动。另外,确认 mysqldump 命令位于 PATH 中,建议用 which mysqldump 输出绝对路径,避免后续在脚本里依赖环境变量而找不到命令。
上面这一段看起来简单,但实际排查时很容易漏掉。尤其是很多服务器通过 Docker 或云镜像初始化,cron 未必默认安装。执行 crontab -l 时如果提示 command not found,就需要先装 cron。安装后还要确认服务已启动,否则任务写进去也不会触发。mysqldump 路径也要注意,用 which mysqldump 得到的结果,在脚本里最好直接使用,或者放到 PATH 中。
容易误判的地方
一个常见坑是 crontab 的环境变量与登录 shell 不同,脚本里的 mysqldump 可能找不到。稳妥做法是在脚本开头显式 export PATH=/usr/local/bin:/usr/bin:/bin,或者直接使用命令的绝对路径。另一个坑是输出重定向:crontab 默认把 stdout 和 stderr 发邮件,如果没配邮件会积累大量垃圾,建议把标准输出和错误分别重定向到日志文件,并定期清理。
这类问题在第一次配置时最常见。你手动执行脚本没问题,但 crontab 的环境变量和登录 shell 不一样,PATH 可能不包含 mysqldump 所在目录。为了避免误判,我习惯在脚本开头写死 PATH,或者用绝对路径。输出重定向也一样,如果不处理,系统会尝试把每封输出邮件发给本地用户,日积月累会占用 inode 空间。建议把标准输出和标准错误分开存,方便对照日志排查。
建议的处理顺序
我的处理顺序是:先写一个可单独执行的备份脚本,手动跑通;再临时配置一个近时间的 crontab 任务,验证完整流程;最后改成目标时间。这样每一步都有明确的检查点,不会把脚本错误和 cron 错误混在一起。
下面是一个备份脚本的最简例子,只做一次全量备份并压缩保留最近 7 份:
#!/bin/bash
export PATH=/usr/local/bin:/usr/bin:/bin
BACKUP_DIR=/data/backup
DB_USER=backup_user
DB_PASS_FILE=/etc/mysql_backup.conf
DB_NAME=myapp
DATE=$(date +%Y%m%d)
mkdir -p "$BACKUP_DIR"
mysqldump \
--single-transaction \
--defaults-extra-file="$DB_PASS_FILE" \
-u"$DB_USER" \
"$DB_NAME" \
| gzip > "$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz"
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 -delete这里把数据库密码放到 /etc/mysql_backup.conf,并在脚本里用 --defaults-extra-file 读取。配置文件内容类似 [client] 段下写 password=xxx,然后把文件权限设为 600。直接写在命令行里容易被进程列表和 shell 历史暴露,不建议这么干。--single-transaction 只对 InnoDB 有效,MyISAM 表仍然会锁表,所以如果库里 Mixed 引擎较多,还是要结合业务低峰期来安排执行时间。
配置与命令示例
编辑 crontab 时建议使用 crontab -e 而非直接修改 /etc/crontab,前者针对当前用户且自动校验语法。填入 0 2 * * * 表示每天凌晨两点执行,务必注意分钟在前,如果写成 * * * * * 会每分钟执行一次导致数据库被频繁锁定。保存后可用 crontab -l 列出确认,必要时检查系统日志 /var/log/cron 看是否触发。
在执行 crontab -e 之前,先确认当前用户是哪个。mysqldump 的权限和备份目录写权限都跟用户相关,建议用专门的备份用户,而不是 root。crontab -e 会打开当前用户的 cron 表,保存时如果有语法错误,一般会直接提示。如果使用 sudo crontab -e,注意操作的是 root 用户的表,任务执行身份也是 root,这会影响配置文件读取权限。
验证方法
配置完成后,不要直接等第二天。可以临时把 cron 表达式改成每分钟执行一次,比如 * * * * *,然后观察 /var/log/cron 或日志文件,确认备份脚本被调用。测试通过后,把时间改回 0 2 * * *。这里要注意,测试时如果脚本本身有写入操作,每分钟执行可能产生多个备份文件,所以建议用一个单独的测试目录或测试库。
备份文件生成后,用 gzip -t 检查压缩包完整性,再用 mysql 命令行导入到临时库验证内容。只看文件大小并不可靠,空文件也可能有非零体积。平时维护时,可以每周用 du -h 对比备份体积,如果连续几天明显变小,多半是脚本参数变了或权限出了问题。
风险与后续维护
备份任务稳定运行后,还要定期看磁盘空间和备份保留策略。上面 find -mtime +7 表示删除 7 天前的文件,具体保留多少份要根据备份总体积和使用场景定。建议保留最近 N 份,并通过计划任务定期执行清理,避免磁盘写满后备份失败。
回滚的时候,先确认备份文件是完整的,再在业务低峰期停止写入,导入备份。导入前把原数据重命名而不是直接删除,这样如果导入失败还能切回来。整个过程要记下当前库的字符集和版本,避免 mysqldump 导出的 SQL 在目标服务器上因为版本差异执行失败。
最后说一个容易忽略的点:crontab 执行结果不代表备份一定有效。备份内容的正确性需要靠恢复演练来保证,建议每个季度做一次从备份恢复到临时库的练习,只检查命令返回值是不够的。