建立备份策略
备份必须定期安排。在MySQL中,可以使用几个工具进行完整备份(在某个时间点上的数据快照)。例如,MySQL Enterprise Backup可以对整个实例进行物理备份,通过优化减少开销并避免在备份InnoDB数据文件时出现中断;mysqldump提供在线逻辑备份。本讨论使用mysqldump。
假设我们在星期日下午1点,低负载时,使用以下命令对所有数据库中的所有InnoDB表进行完整备份:
$> mysqldump --all-databases --master-data --single-transaction > backup_sunday_1_PM.sql
mysqldump生成的结果.sql文件包含一组SQL INSERT语句,可用于在以后的时间重新加载已导出的表。
该备份操作在转储开始时对所有表获取全局读锁(使用FLUSH TABLES WITH READ LOCK)。一旦获取到该锁,就会读取二进制日志坐标并释放锁定。如果在发出FLUSH语句时正在运行长时间的更新语句,则备份操作可能会暂停,直到这些语句完成。之后,转储将变为无锁,不会干扰表的读写操作。
之前假设需要备份的表是InnoDB表,因此--single-transaction使用一致性读取,并保证由mysqldump看到的数据不会更改。(其他客户端对InnoDB表所做的更改不会被mysqldump进程看到。)如果备份操作包括非事务性表,为了保持一致性,在备份期间它们不能更改。例如,在mysql数据库中的MyISAM表中,在备份期间不能对MySQL账户进行管理更改。
全备份是必要的,但并不总是方便创建。它们会产生大型备份文件并需要时间生成。从优化角度来看,每次连续的全备份都包括所有数据,即使是自上次全备份以来未更改的部分。更高效的方法是进行初始的全备份,然后进行增量备份。增量备份较小且生成时间较短。取舍的是,在恢复时,您不能仅通过重新加载全备份来还原数据。您还必须处理增量备份以恢复增量更改。
为了进行增量备份,我们需要保存增量更改。在MySQL中,这些更改在二进制日志中表示,因此MySQL服务器应始终使用--log-bin选项启动以启用该日志。启用二进制日志记录后,服务器在更新数据时将每个数据更改写入文件。查看运行了一些天的MySQL服务器的数据目录,我们可以找到这些MySQL二进制日志文件:
-rw-rw---- 1 guilhem guilhem 1277324 Nov 10 23:59 gbichot2-bin.000001 -rw-rw---- 1 guilhem guilhem 4 Nov 10 23:59 gbichot2-bin.000002 -rw-rw---- 1 guilhem guilhem 79 Nov 11 11:06 gbichot2-bin.000003 -rw-rw---- 1 guilhem guilhem 508 Nov 11 11:08 gbichot2-bin.000004 -rw-rw---- 1 guilhem guilhem 220047446 Nov 12 16:47 gbichot2-bin.000005 -rw-rw---- 1 guilhem guilhem 998412 Nov 14 10:08 gbichot2-bin.000006 -rw-rw---- 1 guilhem guilhem 361 Nov 14 10:07 gbichot2-bin.index
每次重新启动时,MySQL服务器都会使用序列中的下一个编号创建一个新的二进制日志文件。在服务器运行时,您还可以通过发出FLUSH LOGS SQL语句或使用mysqladmin flush-logs命令手动关闭当前的二进制日志文件并启动一个新的日志文件。mysqldump还有一个选项可以刷新日志。数据目录中的.index文件包含目录中所有MySQL二进制日志的列表。
MySQL二进制日志对于恢复很重要,因为它们构成了增量备份集。如果确保在进行全备份时刷新日志,之后创建的二进制日志文件将包含自备份以来所做的所有数据更改。让我们稍微修改前面的mysqldump命令,以便在进行全备份时刷新MySQL二进制日志,并使转储文件包含新的当前二进制日志文件的名称:
$> mysqldump --single-transaction --flush-logs --master-data=2 \ --all-databases > backup_sunday_1_PM.sql
执行此命令后,数据目录中包含一个新的二进制日志文件"gbichot2-bin.000007",因为--flush-logs选项会导致服务器刷新其日志。--master-data选项会导致mysqldump将二进制日志信息写入其输出,因此生成的.sql转储文件包括以下行:
-- Position to start replication or point-in-time recovery from -- CHANGE MASTER TO MASTER_LOG_FILE='gbichot2-bin.000007',MASTER_LOG_POS=4;
由于mysqldump命令进行了全备份,这些行意味着两个事情:
- 转储文件包含在写入gbichot2-bin.000007二进制日志文件或更高版本之前所做的所有更改。
- 备份后记录的所有数据更改不在转储文件中,而是在gbichot2-bin.000007二进制日志文件或更高版本中。
在星期一下午1点,我们可以通过刷新日志以开始新的二进制日志文件来创建增量备份。例如,执行mysqladmin flush-logs命令会创建gbichot2-bin.000008。在星期日下午1点全备份和星期一下午1点之间的所有更改都会写入gbichot2-bin.000007中。这个增量备份很重要,所以最好将其复制到一个安全的位置(例如,将其备份到磁带或DVD上,或者将其复制到另一台机器上)。在星期二下午1点,执行另一个mysqladmin flush-logs命令。在星期一下午1点和星期二下午1点之间的所有更改都会写入gbichot2-bin.000008中(也应该将其复制到安全的位置)。
MySQL二进制日志会占用磁盘空间。为了释放空间,我们需要定期清理它们。一种方法是在不再需要时删除二进制日志,例如在进行全备份时:
$> mysqldump --single-transaction --flush-logs --master-data=2 \ --all-databases --delete-master-logs > backup_sunday_1_PM.sql
注意: 使用mysqldump --delete-master-logs删除MySQL二进制日志可能会很危险,如果您的服务器是一个复制源服务器,因为副本可能尚未完全处理二进制日志的内容。在PURGE BINARY LOGS语句的描述中解释了在删除MySQL二进制日志之前应该进行的验证。