一尘不染

如何优化大型数据库的 mysqldump?

mysql

我有一个 symfony 应用程序,其 InnoDB 数据库约为 2GB,有 57 个表。数据库的大部分大小位于单个表中(~1.2GB)。我目前正在使用 mysqldump 每晚备份数据库。

由于我的 comcast 连接,通常如果我手动运行转储,我与服务器的连接将在转储完成之前超时,导致我不得不重新运行转储。[我目前运行一个每晚执行转储的 cron,这仅适用于我手动运行的转储。]

有没有办法加快连接超时问题的转储,但也可以限制服务器被此进程占用的时间?

顺便说一句,我目前正在努力减少整个数据库的大小以解决这个问题。


阅读 62

收藏
2022-10-09

共1个答案

一尘不染

像这样的转储中的主要瓶颈是驱动器 I/O。您正在读取大量数据并再次写入。您可以通过多种方式加快速度:

  • 确保您的输出将发送到与存储数据库文件的驱动器不同的驱动器 - 这将与旋转磁盘产生巨大差异,因为驱动器磁头不会在读取的位置之间不断滑动以及被写入的位置。
  • mysqldump 的输出将是非常可压缩的,因此如果您不能如上所述将输出与输入分开,请通过管道gzip或类似管道输出。这将减少正在完成的写入量(因此减少整体 IO 负载和磁头移动量),但会花费一些 CPU 时间(无论如何,这些时间你可能有很多空闲时间)。
  • 此外,(以及或代替压缩)通过管道实用程序(如pv )传递输出,该实用程序支持大型写入缓冲区以将写入驱动器的块更多地组合在一起,再次减少磁头移动延迟的影响 - 这将使如果使用该--quick选项来减少备份大表对 RAM 的影响,则会有很大的不同)。
  • 仅当 IO 负载较低时才运行备份过程。

不过,您可能正在解决错误的问题:解决连接断开问题可能更容易(尽管减少备份施加的 I/O 负载将有助于减少您对其他用户的影响,因此无论如何都值得尝试)。您可以通过screen(或类似的工具,如tmux)运行手动备份吗?这样,如果您与服务器的连接断开,您只需重新连接并重新连接到screen会话,而不会中断任何进程。

如果您直接通过连接发送数据(即您在本地计算机上针对远程数据库运行 mysqldump,因此转储出现在本地),您最好先在服务器上运行转储,根据需要进行压缩,然后传输使用支持部分传输的工具(例如rsync)通过网络传输数据,因此如果连接中断中断传输,您可以恢复传输(而不是重新启动)。

作为您“减少整个数据库的大小以解决此问题”的一部分,我猜您的大部分数据不会改变。您可能可以将 1.2Gb 的一大块从该主表移到另一个表中,并将其从mysqldump调用复制的那些中删除。如果这些数据从不更改,则无需每次都备份此数据。以这种方式在表和数据库之间拆分数据通常称为数据分区,还可以让您将数据和 I/O 负载分散到多个驱动器上。高端数据库内置了对自动分区的支持,但在 mysql 中,您可能必须手动执行此操作并更改数据访问层以解决此问题。

偏离本网站的主题(因此您可能应该向 ServerFault 或 SuperUser 询问您是否需要更多详细信息):如果您似乎由于不活动而失去连接,请检查您的 SSH 服务器和 SSH 客户端中的选项以进行确保启用并经常发送保持活动数据包。如果即使连接处于活动状态也看到丢包,您也可以尝试使用 OpenVPN 或类似方法来包装连接 - 如果您的整个连接断开几秒钟,它应该可以处理短暂的丢包,甚至是完全丢包,例如 SSH 客户端和服务器没有注意到。

2022-10-09