通过ZFS快照备份MySQL数据库


12

我发现许多网站都在谈论完全做到这一点,但是我缺少一些重要的细节。一般步骤是

  • 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之类的工具进行热备份并拍摄备份快照,但是我不希望为将所有数据写入第二个位置而进行快照的费用。


为什么有静态的表格列表?您当然可以在运行时动态生成列表。
EEAA

1
数据库是在VM上还是在裸机上?存储器是否在同一台计算机上?
迈克尔·汉普顿

EEAA,很公平。
安迪·舒尔曼

Michael,数据库和ZFS盒是不同的机器,但两者都不是虚拟化的。
安迪·舒尔曼

@AndyShulman我认为您应该更好地解释布局。这没有道理。
ewwhite

Answers:


4

如果仅对所有表使用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


随着MySQL 8中引入的数据字典,现在甚至DDL(模式修改)操作都是原子的。在此之前,文件系统快照期间的DDL操作可能会给出部分提交(即损坏)的结果。
伯尼

13

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

手册https://dev.mysql.com/doc/refman/5.5/en/backup-methods.html表示带有读取锁的FLUSH TABLES特别适用于ZFS快照。

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

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

  1. 在客户端程序中,执行FLUSH TABLES WITH READ LOCK
  2. 从另一个外壳执行安装vxfs快照。
  3. 从第一个客户端执行UNLOCK TABLES
  4. 从快照复制文件。
  5. 卸载快照。

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

这是一种荒谬的,他们离开了你所需要的事实,FLUSH TABLES table_a, table_b, table_c FOR EXPORTInnoDB的这些指令。必须像这样指定每个表也是愚蠢的。但是,正如EEAA所说,您可以相当轻松地开始备份时生成表列表。

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

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

我说容易,不复杂,等等。我假设您具有一些基本的编程或良好的脚本编写能力。


我曾希望在Bash中保留这样一个概念上简单的脚本,但是您是对的,切换语言可以使此操作更加容易。我可能读错了您的答案,但看起来您是在说我需要先执行两个FLUSH TABLES WITH READ LOCK,然后再执行FLUSH TABLES...FOR EXPORT,而我对MySQL手册的阅读说,只需要执行一次。
安迪·舒尔曼

对不起,我不清楚。我只是在阅读手册,它说了两件事。我想你是正确的,只需要稍后。但是所有表应锁定在一个命令中。
Ryan Babchishin

1
考虑到文档不是很清楚,需要锁定整个数据库,并且在拍摄快照时必须维护数据库连接,因此关闭数据库,备份数据库并重新启动似乎更容易。它。
安德鲁·亨利

2
@安德鲁叹息...我明白了。但这会很慢,导致连接断开/失败,而且我已经看到它导致数据库无法正确恢复(不利于自动化)。从mysql / oracle那里得到一个明确的答案将是很好的。他们必须有一个邮件列表。
瑞安·巴布钦

7

我扯下并适于猛砸一个概念上简单的脚本,我在另一台服务器上发现故障通过托比亚。它应该可以让您达到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两台计算机都需要访问指向的文件,您应该能够轻松地完成此操作,因为它们都可以访问一个公共数据集(尽管它们可能使用不同的路径,所以您应该对此加以考虑)。


我不知道MySQL脚本,所以这可能是一个愚蠢的主意,但是您不能只system zfs snapshot...在主脚本中做吗?还是快照必须在单独的过程中运行?
TripeHound16年

@Tripehound两者都需要以某种方式并行发生
Ryan Babchishin 16/09/26

@RyanBabchishin我认为他是正确的。该SYSTEM命令在本地运行事物。如果我在FreeBSD机器上运行mysql客户端并执行LOCK; SYSTEM zfs snapshot; UNLOCK,那似乎就可以了。
安迪·舒尔曼

@安迪我刚刚说过,它们需要并行进行。不管你怎么做。
瑞安·巴布钦

2

对于myisam,您需要带有READ LOCK的FLUSH TABLES,因为它不记录日志。

IMO根本不需要innodb,因为它是日志。无论如何,它都是一致的,只要在快照的原子瞬间发生任何事情,它就会自动回滚日志。

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


2

这是我的解决方案,如何在保持锁定的同时创建ZFS快照:

mysql << EOF
    FLUSH TABLES WITH READ LOCK;
    system zfs snapshot data/db@snapname
    UNLOCK TABLES;
EOF
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.