转储和gzipping MySQL db(使用Python子进程)有时会导致文件损坏

时间:2015-07-14 17:36:05

标签: python mysql amazon-s3 subprocess gzip

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

  1. Cron每天工作一次
  2. 转储文件已压缩并存档到Amazon S3
  3. 当我需要从备份恢复时,会发生以下情况..

    1. 连接到Amazon S3
    2. 从相应的存储桶下载压缩转储文件
    3. 解压缩文件并从该文件恢复数据库。
    4. 发生了什么:一切似乎都很有效。我使用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作为安全漏洞,虽然在这种情况下它是安全的,因为我只能访问服务器并负责配置文件和输入。

1 个答案:

答案 0 :(得分:1)

根据J.F Sebastian对我原来问题的评论,我已经知道subprocess.Popen()立即返回。

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

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

用户BK435曾建议将正在运行的数据库数据文件的副本作为替代方案,但该注释已被否定/删除。在其中,他提到将mysqldump从正在运行的数据库中删除并不是一个好主意,但我没有找到证据支持这是一个坏主意。它确实锁定了表格,但我很好,应用程序每晚都会停机几分钟。