我发现许多网站都在谈论这样做,但我错过了一些重要的细节。一般步骤是
- 跑
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 之类的工具进行热备份并拍摄备份快照,但我不想支付将所有数据写入第二个位置的成本,只是为了对其进行快照。
您需要一个完整的数据库锁来一致地备份(大多数)数据库。
手册https://dev.mysql.com/doc/refman/5.5/en/backup-methods.html说FLUSH TABLES WITH READ LOCK特别适用于 ZFS 快照。
他们从这些说明中忽略了您
FLUSH TABLES table_a, table_b, table_c FOR EXPORT
需要InnoDB的事实,这有点荒谬。必须像这样指定每个表也是愚蠢的。但正如 EEAA 所说,您可以在开始备份时相当轻松地生成一个表列表。至于持有锁,您必须在执行快照时保持数据库连接处于活动状态
一般来说,我会使用 Perl 或其他可以连接、锁定数据库并在保持数据库连接的同时拍摄快照、然后解锁和断开连接的编程语言。这并不复杂。我敢打赌,已经有工具可以做到这一点,但编写一个很容易。
我说了几次简单,不复杂等。我假设你有一些基本的编程或良好的脚本技能。
我在 Bash 中抄袭并改编了一个概念上简单的脚本,我在Tobia的另一篇 Server Fault帖子中找到了该脚本。它应该能让你到达那里的大约 90%。
在这里,
mysql
您使用的命令在后台运行并触及文件。它在后台等待文件消失,然后退出并解锁表。同时主脚本等待文件存在,然后创建快照并删除文件。所指向的文件
$mysql_locked
需要两台机器都可以访问,你应该能够很容易地做到这一点,因为它们都可以访问一个公共数据集(尽管它们可能使用不同的路径,你应该考虑到这一点)。如果您只对所有表使用 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
这是我如何在保持锁定的同时创建 ZFS 快照的解决方案:
对于 myisam,您需要 FLUSH TABLES WITH READ LOCK,因为它不是日志记录。
IMO,您根本不需要任何用于 innodb 的东西,因为它是日志。无论如何它都会保持一致,如果在您快照的原子瞬间发生任何事情,它就会自动回滚日志。
如果您想要应用程序级别的一致性,您的应用程序应该使用事务。如果您的应用程序使用事务和 innodb,任何快照都将一致地自动询问应用程序级别的方式。
由于几年前我们在 innoDB 的 FLUSH TABLES WITH READ LOCK 上也遇到了问题,而且我们也不想依赖 innoDB 从不一致的数据文件中恢复的能力,所以我们做了以下事情:使用第二个 mariadb/mysql数据库计算机配置为辅助(以前称为“从”)。每当您想要制作 zfs 快照时,我们只需关闭辅助节点上的 mariadb/mysql,然后制作 zfs 快照,然后再次启动 mariadb/mysql。
该设置使用 mysqld_multi 运行了大约 4 年(用于在同一台机器上但在不同端口上运行多个数据库实例),没有任何问题。此外,我们想立即将 zfs 快照用作可写的 mariaDB/mysql 实例。因此,我们立即从 zfs-snapshot 中创建一个 zfs-clone,并使用刚刚创建的 zfs-clone 作为其数据目录来启动一个 mariaDB-Docker 容器。此外,我们使用单独的 BindDNS 和路由来使 mariaDB-Docker-container 在我们的内部网络中以 DNS 名称可用。因此,我们可以从内部办公网络的任何地方访问数据库副本以进行读/写。(见https://github.com/ggtools/docker-tools/blob/master/dockerDDNS.py)
这对我们的软件开发人员来说是一个很棒的工具:他们可以在几秒钟内请求数百 GB 甚至 TB 大的 mysqsl/mariadb 实例的完整副本,用于测试和开发目的。
所有这些都由一些 ruby 脚本自动完成,这些脚本本身作为 Jenkins/Hudson Job 提供给开发人员。通过这种方式,我们为开发人员提供了一个漂亮且易于使用的 web-UI,用于在需要时制作 DB-Copys。