备份脚本必须捕获subprocess真实退出码、用utc时间戳命名、流式gzip压缩、按文件名时间戳清理旧备份,并验证恢复可用性。

备份脚本必须捕获 subprocess 的真实退出码
很多脚本用 os.system() 或简单 subprocess.run() 调用 mysqldump,但没检查返回值——哪怕 mysqldump 因权限不足、表被锁或网络中断而失败,脚本仍会继续执行压缩、上传等后续步骤,最终生成一个空的或损坏的备份文件。
正确做法是显式捕获 returncode,并区分常见错误码:
-
returncode == 0:成功 -
returncode == 2:不能连接 MySQL(检查host、user、password) -
returncode == 4:无法读取表结构(常见于权限不足,需确认用户有SELECT和LOCK TABLES权限) -
returncode == 5:输出写入失败(磁盘满、目录无写权限)
示例关键片段:
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.returncode != 0:
logger.error(f"mysqldump failed: {result.stderr.strip()}")
raise RuntimeError(f"Dump failed with code {result.returncode}")
备份文件名必须包含精确时间戳且避免时区歧义
用 datetime.now().strftime("%Y%m%d_%H%M%S") 生成文件名看似合理,但若服务器时区未设为 UTC 或脚本在不同时区机器上运行,会导致文件名重复或排序错乱——比如跨夏令时切换时,同一秒可能生成两个同名文件,后者覆盖前者。
可靠做法是强制使用 UTC 时间,并确保格式不含分隔符(避免某些存储系统或脚本解析异常):
- 用
datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")(ISO 8601 UTC 格式) - 文件名示例:
backup_dbname_20240521T023015Z.sql.gz - 避免用
%f(微秒),因mysqldump本身不支持亚秒级精度,反而增加不可控变量
gzip 压缩必须流式处理,禁止先写入磁盘再压缩
先生成大体积 .sql 文件、再调用 gzip 命令压缩,会在磁盘上短暂存在未加密的明文数据,且两步之间若中断(如磁盘满、kill -9),留下残缺的 .sql 或 .sql.gz 文件,难以判断是否可用。
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
应让 mysqldump 输出直接通过管道进入 gzip,全程内存/管道流转:
- 命令组合:
mysqldump ... | gzip > backup_20240521T023015Z.sql.gz - Python 中用
subprocess.Popen链式调用,设置stdin=subprocess.PIPE和stdout=subprocess.PIPE,避免 shell 注入风险 - 注意:不要用
shell=True拼接含用户输入的参数,尤其数据库名、用户名——应通过subprocess.run(..., args=[...])安全传参
保留最近 N 个备份时,find 命令容易误删非备份文件
常见写法是 find /path/to/backups -name "*.sql.gz" -mtime +7 -delete,但问题在于:-mtime 基于文件修改时间(mtime),而备份文件解压后重写再压缩,mtime 会被重置;且 NFS 或某些容器挂载卷下 mtime 可能不准。
更可靠的方式是按文件名中的时间戳解析并排序:
- 用 Python 列出所有匹配
backup_*.sql.gz的文件 - 用正则提取
20240521T023015Z,转成datetime对象 - 按时间倒序排列,切片取前 N 个,其余
os.remove() - 避免依赖系统命令,防止不同 Linux 发行版
find行为差异(如 BusyBox vs GNU find)
这步看似多写几行,但能彻底规避“删错文件”或“该删不删”的线上事故。
真正麻烦的不是写备份逻辑,而是验证备份可恢复——每次备份后,至少应在测试库中 mysql 导入一次小样本,确认 SHOW TABLES 和行数一致。这点几乎没人做,但恰恰是“高可靠”的分水岭。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










