【问题标题】:Dumping and gzipping MySQL db (with Python subprocess) sometimes results in corrupted file转储和 gzip 压缩 MySQL 数据库(使用 Python 子进程)有时会导致文件损坏
【发布时间】:2015-07-14 17:36:05
【问题描述】:

我想创建 MySQL 数据库的自动备份。我想要的行为如下

  1. Cron 作业每天运行一次
  2. 转储文件被压缩并存档到Amazon S3

当我需要从备份中恢复时,会发生以下情况..

  1. 连接到 Amazon S3
  2. 从相应的存储桶下载压缩转储文件
  3. 解压缩文件并从该文件恢复数据库。

发生了什么:一切似乎都运行良好。我使用 Python 将所有行为自动化。我已经成功备份,并按预期成功恢复了数据库。

现在我注意到有时 dump-zip-archive 过程会导致无法恢复的转储文件。当我尝试恢复数据库时,我收到错误gzip: myDumpFile.sql.gz: unexpected end of file。我注意到,通常一个不成功的备份文件会比正常工作的文件小(好的:2 Mb。坏的:~600 Kb)。运行 python 脚本以创建损坏的备份时,我没有收到任何错误。

我是怎么做的

我正在使用boto Python 库与Amazon S3 进行通信。实际的转储文件如下创建

import subprocess
...
dump_cmd = ['mysqldump ' +
            '--user={mysql_user} '.format(mysql_user=cfg.DB_USER) +
            '--password={db_pw} '.format(db_pw=cfg.DB_PW) +
            '--host={db_host} '.format(db_host=cfg.DB_HOST) +
            '{db_name} '.format(db_name=cfg.DB_NAME) +
            '| ' +
            'gzip ' +
            '> ' +
            '{filepath}'.format(filepath=self.filename)]
subprocess.Popen(dump_cmd, shell=True)
...

当我要恢复时,从 S3 下载文件并发出以下命令

unzip_cmd = ['gzip -d {filename}'.format(filename=self.filename)]
restore_cmd = ['mysql ' +
               '--user={mysql_user} '.format(mysql_user=cfg.DB_USER) +
               '--password={db_pw} '.format(db_pw=cfg.DB_PW) +
               '--host={db_host} '.format(db_host=cfg.DB_HOST) +
               '{db_name} '.format(db_name=cfg.DB_NAME) +
               '< ' +
               '{filepath}'.format(filepath=self.filename[:-3])]
subprocess.Popen(unzip_cmd, shell=True)
subprocess.Popen(restore_cmd, shell=True)

为什么这有时会导致.gz 文件损坏? CRON 运行它或我手动执行之间没有相关性,好的和坏的转储都来自任何一个。

注意我被警告不要使用shell=True 作为安全漏洞,尽管在这种情况下它是安全的,因为只有我可以访问服务器并负责配置文件和输入。

【问题讨论】:

  • @BK435 我正在从具有活动连接的实时数据库中删除转储
  • @BK435 我没有看过 CRON 运行,但我手动运行过。手动运行随机失败
  • Popen() 立即返回。你试过check_call()吗?
  • @BK435 这是一个危险的建议...您无法安全地复制正在运行的 MySQL 服务器的数据目录作为备份方法。这是不支持的。您对连接计数或超时的推测也不正确。这两种情况都会导致 无错误 gzip 容器,其中包含截断或空的 SQL 语句文件。该错误清楚地表明 gzip 结构已损坏,并且没有传达有关有效负载的信息。

标签: python mysql amazon-s3 subprocess gzip


【解决方案1】:

根据 J.F Sebastian 对我最初问题的评论,我了解到subprocess.Popen() 立即返回。

我的程序正在启动数据库转储,然后立即转到执行所有上传工作的函数。因此,一个不完整的数据库转储被发送到AWS S3。解决方案是添加.wait() 函数。

dc = subprocess.Popen(dump_cmd, shell=True)
dc.wait()

用户BK435 曾建议使用正在运行的数据库数据文件的副本作为替代方案,但该评论已被否定/删除。在其中,他提到从正在运行的数据库中删除 mysqldump 不是一个好主意,但我还没有找到证据支持这是一个坏主意。它确实会锁定表,但我可以让应用程序每晚关闭几分钟。

【讨论】:

  • 1.注意:check_call() 为您拨打 .wait()。看its implementation。 2.如果锁表,使用mysqldump可能是可以的,但不能复制裸db文件(例如,使用cp,rsync)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-22
相关资源
最近更新 更多