通过 ZFS 快照备份 MySQL 数据库

通过 ZFS 快照备份 MySQL 数据库

我发现很多网站都在谈论如何做到这一点,但我错过了一些重要的细节。一般步骤如下

  • 跑步FLUSH TABLES WITH READ LOCK
  • 获取 ZFS 快照
  • 跑步UNLOCK TABLES

各种消息来源都称,我使用的 InnoDB 实际上并不支持FLUSH。MySQL 用户手册指出,有一种FLUSH TABLES...FOR EXPORT适用于 InnoDB 的变体,但这需要单独指定每个表,而不是备份整个数据库。我宁愿避免单独指定每个表,因为表列表很有可能与实际存在的表不同步。

我遇到的另一个问题是,我计划做类似的事情mysql -h"$HOST" -u"$USERNAME" -p"$PASSWORD" --execute="FLUSH TABLES WITH READ LOCK"。但是,这会在会话退出后立即释放锁。这很有意义,但也相当烦人,因为我需要在拍摄快照时持有读取锁。

我的另一个想法是使用 Percona XtraBackup 之类的工具进行热备份并对备份进行快照,但我不想花费成本将所有数据写入第二个位置只是为了对其进行快照。

答案1

如果仅对所有表使用 InnoDB 并设置innodb_flush_log_at_trx_commit为:

  • 1(每次事务提交时,InnoDB 日志缓冲区的内容都会写入日志文件,然后将日志文件刷新到磁盘)或者,
  • 2(每次事务提交后,InnoDB 日志缓冲区的内容都会写入日志文件,并且日志文件大约每秒刷新到磁盘一次),

那么在做快照之前就不需要FLUSH TABLES了,直接运行ZFS快照就行了。InnoDB可以从事务提交日志中恢复数据,不会丢失数据。

参考:https://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit

答案2

您需要一个完整的数据库锁来一致地备份(大多数)数据库。

手册https://dev.mysql.com/doc/refman/5.5/en/backup-methods.html刷新表并加读锁对于 ZFS 快照来说是正确的。

使用文件系统快照进行备份

如果您使用 Veritas 文件系统,则可以进行如下备份:

  1. 从客户端程序执行FLUSH TABLES WITH READ LOCK
  2. 从另一个 shell 执行 mount vxfssnapper。
  3. 从第一个客户端执行UNLOCK TABLES
  4. 从快照复制文件。
  5. 卸载快照。

其他文件系统(例如 LVM 或 ZFS)可能也有类似的快照功能。

这有点荒唐FLUSH TABLES table_a, table_b, table_c FOR EXPORT他们忽略了你需要的事实数据库引擎InnoDB根据这些说明。必须这样指定每个表也很愚蠢。但正如 EEAA 所说,您可以在开始备份时相当轻松地生成表列表。

至于保持锁定,您必须在执行快照时保持数据库连接处于活动状态

通常我会使用 Perl 或其他编程语言,这些语言可以连接、锁定数据库并在保持数据库连接的同时拍摄快照,然后解锁并断开连接。这并不复杂。我敢打赌,已经有一些工具可以做到这一点,但编写一个很容易。

我说了几次“简单”、“不复杂”等等。我假设您具有一些基本的编程或良好的脚本编写技能。

答案3

我抄袭并改编了一个概念上简单的 Bash 脚本,它是我在另一个 Server Fault 中找到的邮政经过托比亚。它应该能帮你完成 90% 的路程。

mysql_locked=/var/run/mysql_locked

# flush & lock MySQL, touch mysql_locked, and wait until it is removed
mysql -hhost -uuser -ppassword -NB <<-EOF &
    flush tables with read lock;
    delimiter ;;
    system touch $mysql_locked
    system while test -e $mysql_locked; do sleep 1; done
    exit
EOF

# wait for the preceding command to touch mysql_locked
while ! test -e $mysql_locked; do sleep 1; done

# take a snapshot of the filesystem, while MySQL is being held locked
zfs snapshot zpool/$dataset@$(date +"%Y-%m-%d_%H:%M")

# unlock MySQL
rm -f $mysql_locked

在这里,mysql您使用的命令在后台运行并触及文件。它在后台等待文件消失,然后退出并解锁表。同时,主脚本等待文件存在,然后创建快照并删除文件。

指向的文件$mysql_locked需要可被两台机器访问,您应该能够轻松地做到这一点,因为它们都可以访问一个公共数据集(尽管它们可能使用不同的路径,您应该考虑到这一点)。

答案4

您需要对 myisam 使用 FLUSH TABLES WITH READ LOCK,因为它不具备日志功能。

在我看来,你根本不需要为 innodb 做任何事情,因为它是日志记录。无论如何它都是一致的,只要在你快照的原子时刻发生任何事情,它就会自动回滚日志。

如果您希望应用程序级别保持一致性,则应用程序应使用事务。如果您的应用程序使用事务和 innodb,则任何快照都将自动保持一致,直至应用程序级别。

相关内容