数据库备份自动化是运维的常见需求,但很多团队只是简单写个脚本丢进 cron,结果备份失败、日志丢失、恢复时才发现备份不可用。本文先明确自动化的边界,再给出可执行的脚本编写与定时任务配置方案,帮助你避开常见坑。
先明确:备份自动化能做什么,不能做什么
自动化可以按时执行备份命令、记录日志、清理旧备份、发送失败告警。但它不能保证备份一定可恢复——这取决于备份工具、存储介质和恢复演练。因此,自动化脚本应当包含校验步骤(如备份文件大小、校验和),并定期做恢复测试。本文不涉及具体数据库的备份命令,但会给出通用的脚本框架。
编写可靠的备份脚本:核心要点
一个可靠的备份脚本至少需要处理:备份命令执行、退出码检查、日志记录、失败时告警。以下以 Python 为例,因为 Python 标准库提供了灵活的日志模块,且跨平台。
使用日志模块记录备份过程
根据 Python Logging 官方文档,日志模块支持分层记录,建议在脚本中创建模块级 logger,并配置 FileHandler 和 StreamHandler。这样既能输出到控制台,也能写入日志文件。例如:
import logging
logging.basicConfig(
filename='backup.log',
level=logging.INFO,
format='%(asctime)s %(levelname)s %(message)s'
)
logger = logging.getLogger(__name__)
logger.info('备份开始')
日志应记录开始时间、结束时间、备份文件路径、大小、校验和等关键信息。OWASP 日志安全速查表指出,日志应包含事件时间、来源、结果等,但避免记录敏感数据(如密码),因此备份脚本日志中不要包含数据库连接字符串或口令。
检查退出码,不只是看命令是否执行
备份命令返回非零退出码时,脚本必须捕获并处理。在 shell 中可以用 set -e,但在 Python 中更推荐使用 subprocess 模块并检查 returncode。例如:
import subprocess
result = subprocess.run(['pg_dump', 'dbname'], capture_output=True)
if result.returncode != 0:
logger.error('备份失败: %s', result.stderr)
exit(1)
else:
logger.info('备份成功')
备份后立即校验文件
备份文件生成后,应检查其是否存在且大小非零。更严谨的做法是计算校验和(如 md5)并记录,以便恢复时验证完整性。若备份工具支持,可启用压缩和加密,但要注意压缩后的文件大小与时间。
配置定时任务:cron 与 systemd timer 的选择
Linux 下最常用的是 cron,但 systemd timer 提供了更精细的控制和日志集成。选择取决于你的环境:如果服务器使用 systemd,推荐使用 timer;否则 cron 更通用。
cron 配置示例
# 每天凌晨 2 点执行备份脚本
0 2 * * * /usr/local/bin/backup.py --config /etc/backup.conf
注意 cron 环境变量有限,脚本中应使用绝对路径,并设置 PATH。cron 执行失败时,默认会发送邮件给 root,但很多服务器未配置邮件服务,因此建议在脚本中自行实现告警(如写入日志文件或调用 Webhook)。
systemd timer 配置示例
创建 service 和 timer 单元:
# /etc/systemd/system/backup.service
[Unit]
Description=Database backup
[Service]
ExecStart=/usr/local/bin/backup.py
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.target
启用 timer:systemctl enable --now backup.timer。systemd 会记录服务的标准输出和错误,可通过 journalctl -u backup 查看,日志整合更方便。
处理备份失败:告警与重试策略
备份失败必须及时通知。最简单的方法是在脚本中发送邮件,但现代运维更常用 Webhook(如钉钉、Slack)。注意不要将敏感信息放入告警消息。
重试策略:对于网络或临时锁导致的失败,可以尝试重试 1-2 次,但要注意避免重复备份造成混乱。建议在日志中记录重试次数,并在最终失败时触发告警。
常见误区与注意事项
- 只备份数据文件,不备份日志:对于数据库,备份日志(如 WAL)是恢复的关键,但很多脚本只做全量备份而忽略增量。可参考 增量备份与差异备份的区别。
- 忽略备份文件的权限:备份文件包含敏感数据,应设置严格的文件权限(如 600),并确保存储目录只有备份用户可读。
- 不测试恢复:备份自动化只是第一步,定期演练恢复流程才能确保备份可用。可参考 备份文件损坏后的修复方法。
- 日志过多或过少:日志应记录关键事件,但避免记录敏感信息。OWASP 建议只记录必要的信息,并确保日志不被篡改。
脚本示例:一个简单的 Python 备份框架
以下是一个结合日志和定时任务的示例,假设使用 PostgreSQL 的 pg_dump:
import logging, subprocess, datetime, hashlib
logging.basicConfig(filename='/var/log/backup.log', level=logging.INFO)
logger = logging.getLogger('backup')
def md5(file_path):
h = hashlib.md5()
with open(file_path, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b""):
h.update(chunk)
return h.hexdigest()
backup_file = f'/backup/db_{datetime.datetime.now():%Y%m%d_%H%M%S}.sql'
logger.info('开始备份')
try:
result = subprocess.run(['pg_dump', 'mydb', '-f', backup_file], capture_output=True, text=True)
if result.returncode == 0:
checksum = md5(backup_file)
logger.info(f'备份成功: {backup_file} MD5: {checksum}')
else:
logger.error(f'备份失败: {result.stderr}')
raise SystemExit(1)
except Exception as e:
logger.exception('备份异常')
raise
注意:此示例省略了配置管理、清理旧备份等,实际使用时需扩展。
总结与进一步思考
数据库备份恢复自动化涉及脚本编写、定时任务、日志与告警等多个环节。本文给出的方案是通用的,但具体数据库(如 MySQL、PostgreSQL、MongoDB)的备份命令和参数不同,需要结合官方文档调整。此外,备份自动化不是一劳永逸,应定期审查日志、测试恢复,并关注存储容量。若遇到备份失败或恢复问题,可参考 常见故障排查指南。
参考资料
延伸阅读
