对于任何 DBA 来说,最重要的任务是备份数据。正确且经过测试的备份和恢复程序可以挽救一家公司,从而挽救一份工作。操作失误时有发生,软硬件故障时有发生,自然灾难也会发生。MySQL是一个强大的软件,但它并非完全没有错误或崩溃。因此,了解为什么需要执行备份以及了解执行此操作的各种方法至关重要。
除了保留数据库内容外,大多数备份方法还可以用于另一个重要目的:在不同系统之间复制数据库内容。虽然可能不如在损坏发生时挽救这一条那么重要,但这种复制是绝大多数数据库操作员的例行操作。开发人员将需要使用与生产类似的下游环境。QA 人员可能需要一个持续时间为一小时的不稳定环境。分析可以在专用主机上运行。其中一些任务可以通过复制来解决,但任何副本首先从恢复的备份开始。
本章首先简要回顾两种主要的备份类型并讨论它们的基本属性。然后查看 MySQL 世界中用于备份和恢复的一些可用工具。涵盖每个工具及其参数超出了本书的范围,但在本章结束时,您应该知道如何备份和恢复 MySQL 数据。我们还将看到一些基本的数据传输场景。最后,本章概述了一个强大的备份架构,您可以将其用作工作的基础。
本章末尾的中概述了我们认为是一个好的备份策略。我们认为,在决定策略之前,了解工具和活动部件非常重要,因此该部分排在最后。
物理和逻辑备份
从广义上讲,大多数(如果不是全部)备份工具都适合两大类:逻辑和物理。逻辑备份对内部结构进行操作:数据库(模式)、表、视图、用户和其他对象。物理备份与数据库结构的操作系统端表示有关:数据文件、事务日志等。
用一个例子来解释可能更容易。想象一下在 MySQL 数据库中备份单个 MyISAM 表。正如您将在本章后面看到的,InnoDB 存储引擎要正确备份更加复杂。知道 MyISAM 不是事务性的,并且没有对该表的持续写入,我们可以继续复制与其相关的文件。这样做时,我们创建了表的物理备份。我们可以继续运行SELECT *和SHOW CREATE TABLE针对该表的语句,并以某种方式保留这些语句的输出。这是一种非常基本的逻辑备份形式。当然,这些只是简单的例子,实际上获取这两种备份的过程会更加复杂和微妙。但是,这些虚构备份之间的概念差异可以转移并应用于任何逻辑和物理备份。
逻辑备份
逻辑备份与实际数据有关,而不是它的物理表示。正如您已经看到的,此类备份不会复制任何现有的数据库文件,而是依靠查询或其他方式来获取所需的数据库内容。结果通常是一些文本表示,尽管这不被允许,并且逻辑备份的输出很可能是二进制编码的。让我们看看更多关于此类备份的示例,然后讨论它们的属性。
以下是逻辑备份的一些示例:
-
使用
SELECT ... INTO OUTFILE
语句查询表数据并将其保存到外部文件中。 -
保存为 SQL 语句的表或任何其他对象的定义。
-
针对数据库和空表运行的一个或多个
INSERT
SQL 语句将填充该表,直到保留状态。 -
记录曾经运行过的所有修改数据或架构对象的语句,这些语句涉及特定表或数据库。我们指的是 DML(数据修改语言)和 DDL(数据定义语言)命令。到目前为止,您应该熟悉中介绍的两种类型。
注意
最后一个示例实际上代表了MySQL中复制和时间点恢复工作的一种方式。我们稍后将讨论这些主题,您将看到术语""不仅适用于备份。
逻辑备份的恢复通常是执行一个或多个 SQL 语句。继续我们之前的示例,让我们回顾一下它们的恢复情况:
-
可以使用
LOAD DATA INFILE
命令将文件中的数据加载到表中。 -
可以通过运行 DDL SQL 语句来创建或重新创建表。
-
INSERT
SQL 语句可以使用mysql
CLI 或任何其他客户端执行。 -
重播数据库中运行的所有语句会将其还原到最后一个语句之后的状态。
逻辑备份具有一些有趣的属性,使其在某些情况下非常有用。通常,逻辑备份是某种形式的文本文件,主要是一堆SQL语句。然而,这不是必需的,也不是一个定义属性,尽管通常是有用的属性。创建逻辑备份的过程通常也是执行某些查询的过程。这些都是重要的功能,因为它们允许高度的灵活性和便携性。
逻辑备份非常灵活,因为它们使备份数据库的一部分变得非常容易。例如,可以备份不包含其内容的架构对象,或者轻松仅备份数据库的几个表。更重要的是,您可以备份表的一部分数据,这在物理备份中通常是不可能的。备份文件准备就绪后,某些工具可以手动或自动查看和修改它,这是数据库文件副本不容易完成的。
可移植性来自这样一个事实,即逻辑备份可以轻松加载到在不同操作系统和体系结构上运行的不同版本的MySQL中。通过一些修改,您实际上可以将从一个RDBMS创建的逻辑备份加载到一个完全不同的RDBMS中。由于这一事实,大多数数据库迁移工具在内部使用逻辑复制。此属性还使此备份类型适用于异地备份云托管数据库,以及它们之间的迁移。
逻辑备份具有一个有趣的属性,因为它们可以有效地打击。这里的损坏意味着物理数据文件的任何类型的实际物理损坏。例如,软件中的错误或存储介质的逐渐退化可能会引入数据错误。腐败及其对应物——廉正——的议题非常广泛,但这种简短的解释对我们来说应该足够了。
数据文件损坏后,数据库可能无法从中读取数据并提供查询服务。由于损坏往往是悄无声息发生的,因此您可能不知道它是何时发生的。但是,如果生成逻辑备份时没有错误,则意味着它声音良好且具有良好的数据。(任何非主索引,有关详细信息,请参见")中可能会发生损坏,因此执行完整表扫描的逻辑备份可能不会遇到错误并正常生成。简而言之,逻辑备份将帮助您及早发现损坏(因为它会扫描所有表),或者实际上可以帮助您保存数据(因为最后一次成功的逻辑备份将具有声音数据副本)。
所有逻辑备份的固有问题都来自这样一个事实,即它们是通过对正在运行的数据库系统执行 SQL 语句来创建和还原的。虽然这允许灵活性和可移植性,但这也意味着这些备份会导致数据库负载,并且通常非常慢。当有人运行查询时,DBA总是皱着眉头,不分青红皂白地从表中读取所有数据,而这正是逻辑备份工具通常做的事情。逻辑备份的还原操作通常会导致对每个语句的解释和运行,就好像它来自常规客户端一样。这并不意味着逻辑备份不好或不应该使用,但这是必须记住的权衡。
物理备份
逻辑备份全都与数据有关,如数据库内容,而物理备份则与操作系统文件和内部 RDBMS 工作模式中的数据有关。请记住,在备份 MyISAM 表的示例中,物理备份是代表该表的文件的副本。大多数此类备份和工具都与复制和传输全部或部分数据库文件有关。
物理备份的一些示例包括:
-
冷数据库目录复制,意味着在数据库关闭时进行,而不是在数据库运行时进行热——完成。
-
数据库使用的卷和文件系统的存储快照。
-
表数据文件的副本。
-
某种形式的数据库数据文件更改流,大多数 RDBMS 使用这样的流进行崩溃恢复,有时用于复制。InnoDB 的重做日志是一个类似的概念。
物理备份的恢复通常通过复制文件并使其保持一致来完成。继续我们的示例,让我们回顾一下它们的恢复情况:
-
冷拷贝可以移动到所需的位置或服务器,然后由MySQL实例(新旧)用作数据目录。
-
快照可以就地还原,也可以在另一个卷上还原,然后由MySQL使用。
-
表文件可以代替现有的表文件。
-
针对数据文件重播更改流会将其状态恢复到最后一个时间点。
在这些示例中,我们展示了可以执行的最简单的物理备份:冷数据库目录备份。是的,它简单而基本,但它是一个非常强大的工具。
与逻辑备份不同,物理备份非常严格,在控制可以备份的内容和可以使用备份的位置方面几乎没有余地。一般来说,大多数物理备份只能用于还原数据库或表的完全相同的状态。通常,这些备份还会对目标数据库软件版本和操作系统施加限制。通过一些工作,您可以将逻辑备份从MySQL还原到PostgreSQL。但是,如果在Windows上恢复,在Linux上完成的MySQL数据目录的冷副本可能无法正常工作,尽管它实际上可能有效。如果您没有对数据库服务器的物理访问权限,则无法进行物理备份。这意味着在云中的托管数据库上执行此类备份是不可能的:供应商可能在后台执行物理备份,但您可能没有办法将它们取出。
由于物理备份本质上是原始备份页的全部或子集的副本,因此原始备份中存在的任何损坏都将包含在备份中。请务必记住这一点,因为此属性使物理备份不适合规避数据讹误。
您可能想知道为什么会使用这种看似不方便的备份方式。原因是物理备份速度很快。在操作系统甚至存储级别上运行,物理备份方法有时是实际备份数据库的唯一可能方法。例如,数 TB 卷的存储快照可能需要几秒钟或几分钟,而查询和流式传输该数据以进行逻辑备份可能需要数小时或数天。恢复也是如此。
逻辑和物理备份概述
我们现在已经介绍了两类备份,并准备在MySQL世界中转到用于这些备份的实际工具。但是,在执行此操作之前,让我们通过列出逻辑备份工具和物理备份工具的属性来总结它们之间的差异。
逻辑备份的属性:
-
逻辑结构的描述和内容
-
获取和恢复相对较慢
-
非常灵活,允许重命名对象,合并单独的源,执行部分还原等
-
人类可读和可编辑
-
通常不绑定到特定的数据库版本或平台
-
可以从损坏的表中提取数据并防止损坏
-
适用于备份远程数据库(例如,云)
物理备份的属性:
-
数据、文件或整个文件系统/卷部分的逐字节拷贝
-
快速获取和恢复
-
操作繁琐
-
提供很少的灵活性,在恢复时总是会导致相同的结构
-
通常不允许简单的跨平台甚至跨版本可移植性
-
备份将包括损坏的页面
-
无法在没有操作系统访问权限的情况下备份远程数据库
提示
这些做法并不冲突。实际上,通常最好定期执行这两种类型的备份。它们服务于不同的目的,满足不同的要求。
复制作为备份工具
复制是一个非常广泛的主题,接下来的章节将详细介绍。在本节中,我们将简要讨论复制与备份和恢复数据库的概念之间的关系。
注意
在MySQL世界中,复制是一种逻辑备份。这是因为它基于传输逻辑 SQL 语句。
简而言之,复制不能代替进行备份。的细节是这样的,它们会导致目标数据库的完整或部分副本。这使您可以在涉及MySQL的许多(但不是全部)可能的故障场景中使用复制。让我们回顾两个例子。它们在本章后面的内容中也将有所帮助。
基础架构故障
基础设施容易发生故障:驱动器损坏,停电,发生火灾。几乎没有一个系统可以提供100%的正常运行时间,只有分布广泛的系统才能接近。这意味着最终,数据库都将由于其主机服务器故障而崩溃。在最好的情况下,重新启动可能就足够了。在糟糕的情况下,部分或全部数据可能会消失。
还原和恢复备份绝不是即时操作。在复制环境中,可以执行称为的特殊操作来放置副本来代替发生故障的数据库。在许多情况下,切换可以节省大量时间,并允许在故障系统上工作而不会太匆忙。
想象一下,设置有两个运行MySQL的相同服务器。一个是专用的主数据库,它接收所有连接并处理所有查询。另一个是副本。有一种机制可以将连接重定向到副本,切换会导致 5 分钟的停机时间。
有一天,主服务器中的硬盘驱动器坏了。这是一个简单的服务器,因此仅此一项就会导致崩溃和停机。监视可以捕获问题,DBA 会立即了解,要还原该服务器上的数据库,他们需要安装新磁盘,然后还原并恢复最近的备份。整个操作将需要几个小时。
在这种情况下,切换到副本是一个好主意,因为它可以节省大量宝贵的正常运行时间。
部署错误
软件错误是生活中必须接受的事实。系统越复杂,可能的逻辑错误的发生率就越高。虽然我们都努力限制和减少错误,但我们必须了解它们会发生,并相应地进行计划。
假设发布了包含数据库迁移脚本的应用程序的新版本。即使新版本和脚本都在下游环境中进行了测试,也存在一个错误。迁移会不可挽回地损坏所有具有"特殊"非 ascii 符号的客户姓氏。由于脚本成功完成,因此损坏是无声的,并且一周后才被一个愤怒的客户注意到该问题,该客户的姓名现在不正确。
即使存在生产数据库的副本,它具有相同的数据和相同的逻辑损坏。在这种情况下,切换到副本济于事,并且必须还原在迁移之前执行的备份才能获得正确姓氏的列表。
注意
有一种方法可以使延迟副本保护您免受此类情况的影响,但是延迟的时间越长,操作此类副本的实用性就越低。您可以创建延迟一周的副本,但可能需要一小时前的数据。通常,副本延迟以分钟和小时为单位进行测量。
刚才讨论的两种故障场景涵盖了两个不同的领域:物理和逻辑。复制非常适合在发生物理问题时提供保护,而它没有(或很少)提供针对逻辑问题的保护。复制是一个有用的工具,但它不能替代备份。
mysqldump程序
最重要的逻辑备份类型,也可能是在线备份数据库的最简单方法是将其内容转储为 SQL 语句。计算中的转储通常是指输出某个系统或其部分的内容,转储就是结果。在数据库世界中,转储通常是逻辑备份,而转储是获取此类备份的操作。此类备份的恢复包括将这些语句应用于数据库。您可以手动生成转储,例如,使用SHOW CREATE TABLE和一些CONCAT从表中的数据行 获取INSERT语句,如下所示:
mysql> SHOW CREATE TABLE sakila.actor\G
*************************** 1. row ***************************
Table: actor
Create Table: CREATE TABLE `actor` (
`actor_id` smallint unsigned NOT NULL AUTO_INCREMENT,
`first_name` varchar(45) NOT NULL,
`last_name` varchar(45) NOT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`actor_id`),
KEY `idx_actor_last_name` (`last_name`)
) ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)
mysql> SELECT CONCAT("INSERT INTO actor VALUES",
-> "(",actor_id,",'",first_name,"','",
-> last_name,"','",last_update,"');")
-> AS insert_statement FROM actor LIMIT 1\G
*************************** 1. row ***************************
insert_statement: INSERT INTO actor VALUES
(1,'PENELOPE','GUINESS','2006-02-15 04:34:33');
1 row in set (0.00 sec)
然而,这很快变得非常不切实际。此外,还有更多的事情需要考虑:语句的顺序,以便在恢复时INSERT 在创建表之前不会运行,以及所有权和一致性。尽管手动生成逻辑备份有助于理解,但它既乏味又容易出错。MySQL 捆绑了一个强大的逻辑备份工具mysqldump ,它隐藏了大部分的复杂性。
与 MySQL 捆绑的mysqldump程序允许您从正在运行的数据库实例中生成转储。mysqldump的输出是一些 SQL 语句,这些语句以后可以应用于同一个或另一个 MySQL 实例。mysqldump是一个跨平台的工具,可在 MySQL 服务器本身可用的所有操作系统上使用。由于生成的备份文件只是大量文本,因此它也与平台无关。
mysqldump 的命令行参数很多,因此在开始使用该工具之前查看MySQL 参考手册总是明智的。然而,最基本的场景只需要一个参数:目标数据库名称。
注意
mysqldump 的输出很长,不适合在书籍中打印。在这里和其他地方,输出被截断为仅包含我们感兴趣的行。
在以下示例中,调用mysqldump 时不进行输出重定向,该工具会将所有语句打印到标准输出:
$ mysqldump sakila
...
--
-- Table structure for table `actor`
--
DROP TABLE IF EXISTS `actor`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `actor` (
`actor_id` smallint unsigned NOT NULL AUTO_INCREMENT,
`first_name` varchar(45) NOT NULL,
`last_name` varchar(45) NOT NULL,
`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`actor_id`),
KEY `idx_actor_last_name` (`last_name`)
) ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_0900_ai_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `actor`
--
LOCK TABLES `actor` WRITE;
/*!40000 ALTER TABLE `actor` DISABLE KEYS */;
INSERT INTO `actor` VALUES
(1,'PENELOPE','GUINESS','2006-02-15 01:34:33'),
(2,'NICK','WAHLBERG','2006-02-15 01:34:33'),
...
(200,'THORA','TEMPLE','2006-02-15 01:34:33');
/*!40000 ALTER TABLE `actor` ENABLE KEYS */;
UNLOCK TABLES;
...
您可能会注意到此输出可能比您预期的更微妙。例如,有一个DROP TABLE IF EXISTS语句,当表确实存在于目标上时,它可以防止以下CREATE出错。LOCK 和UNLOCK表语句将提高数据插入性能,等等。
说到模式结构,可以生成没有数据的转储。这对于创建数据库的逻辑克隆非常有用,例如,用于开发环境。像这样的灵活性是逻辑备份和mysqldump的关键特性之一:
$ mysqldump --no-data sakila
... -- -- Table structure for table `actor` -- DROP TABLE IF EXISTS `actor`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `actor` ( `actor_id` smallint unsigned NOT NULL AUTO_INCREMENT, `first_name` varchar(45) NOT NULL, `last_name` varchar(45) NOT NULL, `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`actor_id`), KEY `idx_actor_last_name` (`last_name`) ) ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Temporary view structure for view `actor_info` -- ...
还可以创建数据库中单个表的转储。在下一个示例中,sakila是一个数据库,而category是一个目标表:
$ mysqldump sakila category
将灵活性提高一个档次,您可以通过指定--where=或-w 参数只从表中转储几行。顾名思义,子句的语法与 SQL 中的WHERE相同:
$ mysqldump sakila actor --where="actor_id > 195"
... -- -- Table structure for table `actor` -- DROP TABLE IF EXISTS `actor`; CREATE TABLE `actor` ( ... -- -- Dumping data for table `actor` -- -- WHERE: actor_id > 195 LOCK TABLES `actor` WRITE; /*!40000 ALTER TABLE `actor` DISABLE KEYS */; INSERT INTO `actor` VALUES (196,'BELA','WALKEN','2006-02-15 09:34:33'), (197,'REESE','WEST','2006-02-15 09:34:33'), (198,'MARY','KEITEL','2006-02-15 09:34:33'), (199,'JULIA','FAWCETT','2006-02-15 09:34:33'), (200,'THORA','TEMPLE','2006-02-15 09:34:33'); /*!40000 ALTER TABLE `actor` ENABLE KEYS */; UNLOCK TABLES; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
到目前为止的示例仅涵盖转储特定数据库:sakila 。有时需要输出每个数据库、每个对象,甚至每个用户。mysqldump能够做到这一点。以下命令将有效地创建数据库实例的完整逻辑备份:
$ mysqldump --all-databases --triggers \ --routines --events > dump.sql
默认情况下会转储触发器,因此此选项不会出现在未来的输出中。如果您不想转储触发器,可以使用--no-triggers 。
然而,这个命令仍然存在一些问题。首先,即使我们已将命令的输出重定向到一个文件,生成的文件也可能很大。然而,它的内容很可能非常适合压缩,尽管这取决于实际数据。不过,压缩输出是个好主意:
$ mysqldump --all-databases \ --routines --events | gzip > dump.sql.gz
在 Windows 上,通过管道压缩输出很困难,因此只需压缩通过运行前一个命令接收到的dump.sql。在 CPU 阻塞的系统上,例如我们在这里使用的小型 VM,压缩可能会显着增加备份过程的时间。这是必须为特定系统进行的权衡:
$ time mysqldump --all-databases \ --routines --events > dump.sql
real 0m24.608s user 0m15.201s sys 0m2.691s
$ time mysqldump --all-databases \ --routines --events | gzip > dump.sql.gz
real 2m2.769s user 2m4.400s sys 0m3.115s
$ ls -lh dump.sql*
-rw... 2.0G ... dump.sql -rw... 794M ... dump.sql.gz
第二个问题是为了保证一致性,表上会加锁,防止在转储数据库时写入(写入其他数据库可以继续)。这对性能和备份一致性都是不利的。生成的转储仅在数据库内一致,而不是在整个实例中一致。这种默认行为是必要的,因为 MySQL 使用的一些存储引擎是非事务性的,主要是较旧的 MyISAM。另一方面,默认的 InnoDB 存储引擎具有允许维护读取快照的 MVCC 模型。
通过将--single-transaction命令行参数传递给mysqldump ,可以利用 InnoDB 的事务功能。但是,这消除了表锁定,从而使非事务表在转储期间容易出现不一致。例如,如果您的系统同时使用 InnoDB 和 MyISAM 表,则可能需要单独转储它们,如果不需要中断写入和一致性。
笔记
尽管--single-transaction确保在mysqldump运行时可以继续写入,但仍有一些警告:并发运行的 DDL 语句可能会导致不一致。和长时间运行的事务,如一个由发起mysqldump的,可以有一个对整个实例性能造成负面影响。
主要使用 InnoDB 表进行系统转储的基本命令如下,该命令保证了对并发写入的影响有限:
$ mysqldump --single-transaction --all-databases \ --routines --events | gzip > dump.sql.gz
在现实世界中,您可能会有更多参数来指定连接选项。您还可以围绕mysqldump语句编写脚本以捕获任何问题并在出现任何问题时通知。
使用--all-databases转储包括内部 MySQL 数据库,例如mysql 、sys 、information_schema 。恢复数据并不总是需要这些信息,并且在恢复到已经有一些数据库的实例时可能有害。但是,您应该记住 MySQL 用户详细信息只会作为mysql数据库的一部分转储。
通常,使用mysqldump及其生成的逻辑备份可以实现以下目的:
·轻松在环境之间传输数据
·由人和程序就地编辑数据。例如,您可以从转储中删除个人或不必要的数据
·查找某些数据文件损坏
·主要数据库版本、不同平台甚至数据库之间的数据传输
使用 mysqldump 引导复制
所述的mysqldump程序可以被用来创建一个副本实例或是空的或是用数据。为方便起见,可以使用多个命令行参数。例如,当指定--master-data时,结果输出将包含一个 SQL 语句 ( CHANGE MASTER TO ),它将在目标实例上正确设置复制坐标。当稍后在目标实例上使用这些坐标开始复制时,数据中将不存在间隙。在基于 GTID 的复制拓扑中,--set-gtid-purged可用于实现相同的结果。但是,即使没有任何额外的命令行参数,mysqldump也会检测到gtid_mode=ON并包含必要的输出。
设置复制的示例在mysqldump
中提供。
从 SQL 转储文件加载数据
执行备份时,始终牢记您这样做是为了以后能够恢复数据,这一点很重要。使用逻辑备份,恢复过程就像将备份文件的内容通过管道传输到 mysql cli一样简单。如前所述,MySQL 必须进行逻辑备份还原这一事实会产生好的和坏的结果:
·您可以在系统的其他部分正常工作时恢复单个对象,这是一个加分项。
·恢复过程效率低下,如果决定插入大量数据,它会像任何普通客户端一样加载系统。那是一个减号。
让我们看一个带有单个数据库备份和恢复的简单示例。正如我们之前看到的,mysqldump会将必要的DROP语句包含到转储中,因此即使对象存在,它们也会成功恢复:
$ mysqldump sakila > /tmp/sakila.sql $ mysql -e "CREATE DATABASE sakila_mod" $ mysql sakila_mod < /tmp/sakila.sql $ mysql sakila_mod -e "SHOW TABLES"
+----------------------------+ | Tables_in_sakila_mod | +----------------------------+ | actor | | actor_info | ... | store | +----------------------------+
恢复像mysqldump或mysqlpump产生的 SQL 转储(在下一节中讨论)是一种资源繁重的操作。默认情况下,它也是一个串行进程,可能需要大量时间。您可以使用一些技巧来加快此过程,但请记住,错误可能会导致数据丢失或错误恢复:
1. 并行恢复每个模式/每个数据库
2. 模式内对象的并行恢复
如果使用mysqldump进行转储是在每个数据库的基础上完成的,那么第一个很容易完成。如果不需要跨数据库的一致性(无法保证),备份过程也可以并行化。以下示例使用&修饰符,它指示 shell 在后台执行前面的命令:
$ mysqldump sakila > /tmp/sakila.sql & $ mysqldump nasa > /tmp/nasa.sql &
结果转储是独立的。除非转储mysql数据库,否则mysqldump不会处理用户和授权,因此您需要注意这一点。恢复同样简单:
$ mysql sakila < /tmp/sakila.sql & $ mysql nasa < /tmp/nasa.sql &
在 Windows 上,还可以使用 PowerShell Start-Process或在更高版本中使用相同的&将命令执行发送到后台。
第二种选择涉及更多。您需要在每个表的基础上进行转储(mysqldump sakila Artists > sakila.artists.sql ),这会导致直接恢复,或者您需要继续编辑转储文件以将其拆分为多个文件. 在极端情况下,您甚至可以在表级别并行化数据插入,尽管这可能不切实际。
尽管这是可行的,但最好使用专门为此任务构建的工具。
mysqlpump
mysqlpump是一个与 MySQL 5.7 及更高版本捆绑的实用程序,它在几个方面改进了mysqldump ,主要是性能和可用性。主要区别如下:
·并行转储能力
·内置转储压缩
·通过延迟创建二级索引提高恢复性能
·更容易控制转储的对象
·修改了转储用户帐户的行为
使用该程序与使用mysqldump非常相似。主要的直接区别是,当没有传递参数时,mysqlpump将默认转储所有数据库(不包括INFORMATION_SCHEMA 、performance_schema 、ndbinfo和sys架构)。其他值得注意的事情是有一个进度指示器并且mysqlpump默认使用两个线程并行转储:
$ mysqlpump > pump.out
Dump progress: 1/2 tables, 0/530419 rows Dump progress: 80/184 tables, 2574413/646260694 rows ... Dump progress: 183/184 tables, 16297773/646260694 rows Dump completed in 10680
mysqlpump中并行的概念稍微复杂一些。您可以在不同数据库之间以及给定数据库内的不同对象之间使用并发。默认情况下,当没有指定其他并行选项时,mysqlpump将使用具有两个并行线程的单个队列来处理所有数据库和用户定义(如果需要)。您可以使用--default-parallelism=N参数控制默认队列的并行级别。为了进一步微调并发性,您可以设置多个并行队列来处理单独的数据库。在选择所需的并发级别时应注意,因为您最终可能会使用大部分数据库资源进行备份运行。
使用mysqlpump时mysqldump 的一个重要区别在于后者如何处理用户帐户。mysqldump仅通过转储mysql.user和其他相关表来管理用户。如果 转储中未包含mysql数据库,则不会保留任何用户信息。mysqlpump通过引入命令行参数--users和--include -users对此进行了改进。第一个告诉实用程序将与用户相关的命令添加到所有用户的转储中,第二个接受用户名列表。这是对旧的做事方式的巨大改进。
让我们结合所有新功能来生成非系统数据库、用户定义的压缩转储,并在此过程中使用并发:
$ mysqlpump --compress-output=zlib --include-users=bob,kate \ --include-databases=sakila,nasa,employees \ --parallel-schemas=2:employees \ --parallel-schemas=sakila,nasa > pump.out
Dump progress: 1/2 tables, 0/331579 rows Dump progress: 19/23 tables, 357923/3959313 rows ... Dump progress: 22/23 tables, 3755358/3959313 rows Dump completed in 10098
注意
mysqlpump输出可以使用 ZLIB 或 LZ4 算法进行压缩。当操作系统级命令lz和openssl zlib不可用时,您可以使用MySQL 发行版中包含的lz4_decompress和zlib_decompress实用程序。
mysqlpump运行产生的转储不适合并行还原,因为其中的数据是交错的。例如,以下是mysqlpump执行的结果,显示在插入不同数据库中的表时创建表:
...,(294975,"1955-07-31","Lucian","Rosis","M","1986-12-08"); CREATE TABLE `sakila`.`store` ( `store_id` tinyint unsigned NOT NULL AUTO_INCREMENT, `manager_staff_id` tinyint unsigned NOT NULL, `address_id` smallint unsigned NOT NULL, `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`store_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ; INSERT INTO `employees`.`employees` VALUES (294976,"1961-03-19","Rayond","Khalid","F","1989-11-03"),...
mysqlpump是对mysqldump的改进,并增加了重要的并发、压缩和对象控制功能。但是,该工具不允许对转储进行并行还原,并且实际上使其成为不可能。还原性能的唯一改进是在主加载完成后添加二级索引。
mydumper 和 myloader
mydumper和myloader都是开源项目mydumper 的一部分。这套工具试图使逻辑备份更高效、更易于管理,并且更面向人类。我们只是简单地提到这个工具——否则,我们很容易在涵盖每一个可能的 MySQL 备份种类的书中用完空间。
可以通过从项目的 github 页面获取最新版本或编译源代码来安装这些程序。在撰写本文时,最新版本在某种程度上落后于 master 的当前开发。“设置 mydumper 和 myloader 实用程序”中提供了分步安装说明?.
我们之前展示了mysqlpump如何提高转储性能,但提到它的交织输出无助于恢复。mydumper将并行转储方法与myloader 的并行还原设置基础相结合。这是通过将每个表转储到一个单独的文件来实现的。
mydumper的默认调用非常简单。该工具尝试连接到数据库,启动一致的转储,并在当前目录下为导出文件创建一个目录。请注意每个表如何拥有自己的文件。默认情况下,mydumper还将转储mysql和sys 数据库。转储操作的默认并行度为 4,这意味着将同时读取 4 个单独的表。在此目录上调用的myloader将能够并行恢复表。
$ mydumper $ ls -ld export*
drwx... export-20210613-204512
$ ls -la export-20210613-204512
... -rw... sakila.actor.sql -rw... sakila.address-schema.sql -rw... sakila.address.sql -rw... sakila.category-schema.sql -rw... sakila.category.sql -rw... sakila.city-schema.sql -rw... sakila.city.sql ...
除了并行转储和恢复功能外,mydumper还具有一些更高级的功能:
·轻量级备份锁支持。Percona Server for MySQL 实现了 Percona XtraBackup 使用的一些额外的轻量级锁定。mydumper在可能的情况下默认使用这些锁。
·当面对长时间的元数据锁定时,mydumper可能会失败或终止长时间运行的查询,从而阻止其运行。
·使用保存点。mydumper使用事务保存点的技巧来最小化元数据锁定。
mydumper和myloader是将逻辑备份功能发挥到极致的高级工具。然而,作为一个社区项目,它们缺乏其他工具提供的文档和润色。另一个主要缺点是缺乏任何支持或保证。尽管如此,它们仍然可以成为数据库操作员工具带的有用补充。
冷备份和文件系统快照
物理备份的基石,冷备份实际上只是数据目录和其他必要文件的副本,在数据库实例关闭时完成。冷备份并不常用,但它可以节省您需要快速创建一致备份的时间。随着数据库现在经常接近数 TB 的大小范围,仅复制文件可能需要很长时间。不过,冷备份还是有它的优点的:
·非常快,可以说是最快的备份方法(除了快照)
·直率
·易于使用,不易出错
·需要完全停机
现代存储系统和一些文件系统具有现成的快照功能。它们允许您利用内部机制创建任意大小卷的近乎即时的副本。每个具有快照功能的系统的属性都会有很大差异,因此我们不可能涵盖所有这些。但是,我们仍然可以从数据库的角度谈谈它们。
大多数快照将是Copy-on-Write(或 COW),并且将在某个时间点内部保持一致。然而,我们已经知道数据库文件在磁盘上是不一致的,尤其是对于像 InnoDB 这样的事务存储引擎。这使得正确获取快照备份有些困难。有两种选择:
冷备份快照
当数据库关闭时,其数据文件可能仍然不完全一致。但是,如果您对所有数据库文件(例如,包括 InnoDB 重做日志)进行快照,它们一起将允许数据库启动。这是很自然的,否则数据库会在每次重启时丢失数据。不要忘记,您可能将数据库文件拆分为多个卷。您将需要拥有所有这些。此方法适用于所有存储引擎。
热备份快照
对于正在运行的数据库,正确拍摄快照比数据库关闭时更具挑战性。如果您的数据库文件位于多个卷上,则您无法保证即使同时启动的快照也将与同一时间点保持一致,这可能会导致灾难性的结果。此外,像 MyISAM 这样的非事务性存储引擎不能保证数据库运行时磁盘上文件的一致性。对于 InnoDB 实际上也是如此,但是 InnoDB 的重做日志始终是一致的(除非禁用了保护措施),而 MyISAM 缺少此功能。
因此,推荐的热备份快照方法是使用一定数量的锁定。由于快照拍摄过程通常很快,因此造成的停机时间应该不会很长:
1. 新建一个会话,用FLUSH TABLES WITH READ LOCK锁定所有表;命令。这个会话不能关闭,否则锁会被释放。
2. 可选地,通过运行SHOW MASTER STATUS 来记录当前的 binlog 位置; 命令。
3. 根据存储系统的手册创建 MySQL 数据库文件所在的所有卷的快照。
4. 使用UNLOCK TABLES解锁表;会话中的命令最初打开。
这种通用方法应该适用于大多数(如果不是全部)能够执行快照的当前存储和文件系统。请注意,它们在实际程序和要求上都略有不同。一些云供应商要求您额外对文件系统执行fsfreeze 。
在生产中实施备份之前,请务必彻底测试备份,并信任它们与您的数据。您只能信任您测试过并且使用起来很舒服的解决方案。复制任意备份策略建议不是一个好主意。
Percona XtraBackup
物理备份的逻辑步骤是实施所谓的“热” ?备份。即,在数据库运行时制作数据库文件的副本。我们已经提到可以复制 MyISAM 表,但这不适用于 InnoDB 和其他事务存储引擎,如 MyRocks。因此,问题是您不能仅仅复制文件,因为数据库一直在发生变化。例如,即使现在没有写入数据库,InnoDB 也可能会在后台刷新一些脏页。您可以测试您的运气并在正在运行的系统下复制数据库目录,然后尝试恢复该目录并使用它启动 MySQL 服务器。有可能,它可能不起作用。虽然它也可以工作,但我们强烈建议不要冒险进行数据库备份。
执行热备份的功能内置于三个主要的 MySQL 备份工具中:Percona XtraBackup、MySQL Enterprise Backup和mariabackup。我们将简要讨论所有这些,但主要集中在 XtraBackup 实用程序上。了解所有工具共享属性很重要,因此了解如何使用一种工具将有助于使用其他工具。
Percona XtraBackup 是一个免费的开源软件,由 Percona 和更广泛的 MySQL 社区维护。该工具能够使用 InnoDB、MyISAM 和 MyRocks 表执行 MySQL 实例的在线备份。该程序仅在 Linux 上可用。请注意,不可能将 XtraBackup 与最新版本的 MariaDB 一起使用:仅支持 MySQL 和 Percona Server。对于 MariaDB,请使用我们在“ mariabackup”中提到的mariabackup实用程序。
下面是XtraBackup的操作本质:
1. 记录当前的LSN—— Log Sequence Number——操作的内部编号。
2. 开始积累 InnoDB重做数据——InnoDB 存储用于崩溃恢复的数据类型。
3. 以最少侵入性的方式锁定表。
4. 复制 InnoDB 表。
5. 完全 锁定非事务引擎表。
6. 复制 MyISAM 表。
7. 解锁所有表。
8. 处理 MyRocks(如果存在)。
9. 将累积的重做数据与复制的数据库文件放在一起。
XtraBackup 和热备份之间的主要思想一般是将逻辑备份的无停机性质与冷备份的性能和相对缺乏性能影响相结合。XtraBackup 不保证不会中断服务,但与常规冷备份相比,它向前迈出了一大步。缺乏性能影响意味着 XtraBackup 将使用一些 CPU 和 IO,但仅需要复制数据库文件。另一方面,逻辑备份必须通过所有数据库内部结构传递每一行,这使得它们本质上很慢。
注意
XtraBackup 需要对数据库文件进行物理访问,不能远程运行。例如,这使得它不适合对托管数据库 (DBaaS) 进行异地备份。但是,一些云供应商允许使用此工具制作的备份导入数据库。
XtraBackup 实用程序在各种 Linux 发行版的存储库中广泛可用,因此可以使用包管理器轻松安装。或者,您可以直接从Percona 网站上的XtraBackup 下载页面下载软件包和二进制分发版。
警告
要备份 MySQL 8,必须使用 XtraBackup 8.0。理想情况下,XtraBackup 和 MySQL 的版本也应该匹配:XtraBackup 8.0.25 保证与 MySQL 8.0.25 一起使用。对于 MySQL 5.7 及更早版本,请使用 XtraBackup 2.4。
备份和恢复
与我们之前提到的其他工具不同,XtraBackup 作为物理备份工具的性质,不仅需要访问 MySQL 服务器,还需要读取数据库文件。在大多数 MySQL 安装中,这通常意味着应该从root用户运行xtrabackup程序,或者必须使用sudo 。我们将 在本节中使用root用户,并使用“登录路径配置文件”中的步骤设置登录路径。
首先,我们需要运行基本的xtrabackup命令:
# xtrabackup --host=127.0.0.1 \ --target-dir=/tmp/backup --backup
... Using server version 8.0.25 210613 22:23:06 Executing LOCK INSTANCE FOR BACKUP... ... 210613 22:23:07 [01] Copying ./sakila/film.ibd to /tmp/backup/sakila/film.ibd 210613 22:23:07 [01] ...done ... 210613 22:23:10 [00] Writing /tmp/backup/xtrabackup_info 210613 22:23:10 [00] ...done xtrabackup: Transaction log of lsn (6438976119) to (6438976129) was copied. 210613 22:23:11 completed OK!
如果登录路径不起作用,您应该使用--user和--password命令行参数将root用户的凭据传递给xtrabackup 。XtraBackup 通常会通过读取默认选项文件来识别目标服务器的数据目录。但是,如果这不起作用,或者您有多个 MySQL 安装,您可能还需要指定--datadir选项。
提示
虽然我们在示例中使用/tmp/backup作为备份的目标路径,但您应该避免将重要文件存储在/tmp 下。对于备份来说尤其如此。
xtrabackup --backup 调用的结果是一堆数据库文件,这些文件实际上在任何时间点都不一致,还有一大块 InnoDB 无法应用的重做数据。
# ls -l /tmp/backup/
... drwxr-x---. 2 root root 160 Jun 13 22:23 mysql -rw-r-----. 1 root root 46137344 Jun 13 22:23 mysql.ibd drwxr-x---. 2 root root 60 Jun 13 22:23 nasa drwxr-x---. 2 root root 580 Jun 13 22:23 sakila drwxr-x---. 2 root root 580 Jun 13 22:23 sakila_mod drwxr-x---. 2 root root 80 Jun 13 22:23 sakila_new drwxr-x---. 2 root root 60 Jun 13 22:23 sys ...
为了使备份为将来的恢复做好准备,必须执行另一个阶段——准备。无需为此连接到 MySQL 服务器:
# xtrabackup --target-dir=/tmp/backup --prepare
... xtrabackup: cd to /tmp/backup/ xtrabackup: This target seems to be not prepared yet. ... Shutdown completed; log sequence number 6438976524 210613 22:32:23 completed OK!
生成的数据目录实际上已经完全可以使用了。你可以启动一个直接指向这个目录的 MySQL 实例,它会起作用。这里犯的一个非常常见的错误是尝试在mysql用户下启动 MySQL 服务器,而恢复和准备的备份由root或其他操作系统用户拥有。确保 根据需要将chown和chmod合并到您的备份恢复过程中。但是,有一个有用的用户体验功能--copy-back可用。xtrabackup保留原始数据库文件布局位置,并使用--copy-back调用会将所有文件恢复到其原始位置:
# xtrabackup --target-dir=/tmp/backup --copy-back
... Original data directory /var/lib/mysql is not empty!
那没有用,因为我们原来的 MySQL 服务器还在运行,而且它的数据目录不是空的。除非目标数据目录为空,否则 XtraBackup 将拒绝恢复备份。这应该可以防止您意外恢复备份。让我们关闭正在运行的 MySQL 服务器,删除或移动它的数据目录,然后恢复备份:
# systemctl stop mysqld # mv /var/lib/mysql /var/lib/mysql_old # xtrabackup --target-dir=/tmp/backup --copy-back
... 210613 22:39:01 [01] Copying ./sakila/actor.ibd to /var/lib/mysql/sakila/actor.ibd 210613 22:39:01 [01] ...done ... 210613 22:39:01 completed OK!
之后,文件位于正确的位置,但归root 所有:
# ls -l /var/lib/mysql/
drwxr-x---. 2 root root 4096 Jun 13 22:39 sakila drwxr-x---. 2 root root 4096 Jun 13 22:38 sakila_mod drwxr-x---. 2 root root 4096 Jun 13 22:39 sakila_new
我们需要将文件的所有者改回mysql (或系统中使用的用户)并修复目录权限。完成后,可以启动 MySQL 并验证数据:
# chown -R mysql:mysql /var/lib/mysql/ # chmod o+rx /var/lib/mysql/ # systemctl start mysqld # mysql sakila -e "SHOW TABLES;"
+----------------------------+ | Tables_in_sakila | +----------------------------+ | actor | ... | store | +----------------------------+
提示
最佳做法是在备份阶段同时进行备份和准备阶段,从而最大限度地减少以后可能出现的意外情况。想象一下,当您尝试恢复一些财务数据时,准备阶段失败了。
高级功能
在本节中,我们将讨论 XtraBackup 的一些更高级的功能。他们不需要使用该工具,我们仅对他们进行简要概述。
数据库文件验证
在执行备份时,XtraBackup 将验证它正在处理的数据文件的所有页面的校验和。这是为了缓解物理备份的固有问题,即它们将包含源数据库的损坏。我们建议使用“测试和验证备份”中显示的其他步骤来增加此检查?.
压缩
尽管复制物理文件比查询数据库快得多,但您可能仍希望提高性能,尤其是在您有空闲容量的情况下。XtraBackup 使用qpress工具进行压缩。这个工具可以从percona-release包中获得。
# xtrabackup --host=127.0.0.1 \ --target-dir=/tmp/backup_compressed/ \ --backup --compress
并行性
可以使用--parallel命令行参数使备份和回拷过程并行。
加密
除了能够使用加密数据库之外,XtraBackup 还可以创建加密备份。
流媒体
XtraBackup 可以以xbstream格式流式传输生成的备份,而不是创建一个充满备份文件的目录。这导致更便携的备份,并允许与xbcloud集成。例如,您可以通过 SSH 流式传输备份。
云端上传
与XtraBackup采取的备份可以被上传到使用任何S3兼容的存储xbcloud 。S3 是 Amazon 的对象存储设施和被许多公司广泛采用的 API。此工具仅适用于通过xbstream流式传输的备份,如前所述。
使用 XtraBackup 进行增量备份
如前所述,由于 XtraBackup 默认工作,热备份仍然是数据库中每个字节信息的副本。但在很多情况下,数据库会以不规则的速度发生变化——新数据被添加,而旧数据变化不大或根本没有变化。添加了一系列财务记录,并修改了帐户,但在给定的一周内,仅更改了百分之几的帐户。因此,改进热备份的下一个合乎逻辑的步骤是执行所谓的增量备份或更改数据的备份的能力。这将允许您通过减少空间需求来更频繁地执行备份。
要使增量备份起作用,您首先需要对数据库进行完整备份,称为基础备份——否则就没有任何可增量的内容。基础备份准备就绪后,您可以执行任意数量的增量备份,每次都包含自上一次以来的更改(或者在第一次增量备份的情况下来自基础备份)。在极端情况下,您可以每分钟创建一个增量备份,实现称为时间点恢复 (PITR) 的东西,但这不是很实用,您很快就会了解到有更好的方法可以做到这一点。
下面是一个 XtraBackup 命令示例,用于创建基本备份和增量备份。注意增量备份如何通过--incremental-basedir参数指向基础备份:
# xtrabackup --host=127.0.0.1 \ --target-dir=/tmp/base_backup --backup # xtrabackup --host=127.0.0.1 --backup \ --incremental-basedir=/tmp/base_backup \ --target-dir=/tmp/inc_backup1
如果检查备份大小,您会发现增量备份与基本备份相比非常小:
# du -sh /tmp/base_backup
2.2G /tmp/base_backup 6.0M /tmp/inc_backup1
让我们创建另一个增量备份。在这种情况下,我们将传递先前增量备份的目录作为基本目录:
完成后,我们可以创建另一个增量备份。我们将从第一个这样的备份开始增量:
# xtrabackup --host=127.0.0.1 --backup \ --incremental-basedir=/tmp/inc_backup1 \ --target-dir=/tmp/inc_backup2
210613 23:32:20 completed OK!
您可能会注意到,可以将原始基本备份的目录指定为每个新增量备份的--incremental-basedir 。事实上,这会产生一个完全有效的备份,它是增量备份的变体(或相反)。此类增量备份包含的更改不是自上次增量备份以来而是自基础备份以来的更改,通常称为累积备份。针对任何先前备份的增量备份是差异备份。累积增量备份通常会占用更多空间,但可以显着减少恢复备份时准备阶段所需的时间。
重要的是,增量备份的准备过程不同于常规备份的准备过程。让我们从基础备份开始准备我们刚刚进行的备份:
# xtrabackup --prepare --apply-log-only \ --target-dir=/tmp/base_backup
该--apply-数只参数告诉xtrabackup不完成的准备过程中,我们仍然需要应用来自增量备份的变化。让我们这样做:
# xtrabackup --prepare --apply-log-only \ --target-dir=/tmp/base_backup \ --incremental-dir=/tmp/inc_backup1 # xtrabackup --prepare --apply-log-only \ --target-dir=/tmp/base_backup \ --incremental-dir=/tmp/inc_backup2
所有命令都应该报告完成 OK!到底。一旦运行--prepare --apply-log-only ,基础备份就会前进到增量备份的点,从而无法将时间点恢复到更早的时间。因此,在执行增量备份时立即准备并不是一个好主意。要完成准备过程,必须正常准备带有从增量备份中应用的更改的基本备份:
# xtrabackup --prepare --target-dir=/tmp/base_backup
一旦基本备份“完全”??准备好后,尝试应用增量备份将失败并显示以下消息:
xtrabackup: This target seems to be already prepared. xtrabackup: error: applying incremental backup needs target prepared with --apply-log-only.
当数据库中的相对更改量很高时,增量备份效率低下。在最坏的情况下,数据库中的每一行都在完整备份和增量备份之间发生了变化,后者实际上只是一个完整备份,存储了 100% 的数据。增量备份在附加大部分数据时最有效,并且被更改的旧数据的相对量较低。对此没有规定,但如果 50% 的数据在基础备份和增量备份之间发生变化,请考虑不使用增量备份。
其他物理备份工具
XtraBackup 不是唯一能够执行热 MySQL 物理备份的可用工具。我们选择使用这个特定工具来解释概念是由我们的经验决定的。然而,这并不意味着其他工具在任何方面都更糟。他们可能会更好。本书篇幅有限,备份的范围很广。我们可以写一本相当数量的备份 MySQL 的书!
也就是说,让我们来看看另外两个现成的物理备份工具。
MySQL Enterprise Backup
该工具简称 MEB,是 Oracle 提供的 MySQL 企业版产品的一部分。它是一个封闭源代码的专有工具,其功能类似于 XtraBackup。您可以在mysql.com 站点上找到有关它的全面文档。目前有两个工具具有相同的功能,因此几乎所有 XtraBackup 涵盖的内容也适用于 MEB。
MEB 的突出特性在于它是真正的跨平台解决方案。XtraBackup 仅适用于 Linux,而 MEB 也适用于 Solaris、Windows、macOS 和 FreeBSD。MEB 不支持除 Oracle 标准之外的 MySQL 版本。
MEB 的一些附加功能在 XtraBackup 中不可用,包括:
·备份进度报告
·离线备份
·通过 Oracle Secure Backups 进行磁带备份
·二进制和中继日志备份
·恢复时表重命名
mariabackup
mariabackup 是 MariaDB 用于备份 MySQL 数据库的工具。最初从 XtraBackup 派生出来,这是一个免费的开源工具,可在 Linux 和 Windows 上使用。mariabackup 的突出特性是它与 MySQL 的 MariaDB 分支的无缝工作,它继续与主流 MySQL 和 Percona Server 显着不同。由于这是 XtraBackup 的直接分支,您可能会发现这些工具的使用方式及其属性有许多相似之处。一些 XtraBackup 的新功能,如备份加密和二级索引遗漏,在 mariabackup 中不存在。但是,目前无法使用 XtraBackup 来备份 MariaDB。
时间点恢复
现在您已经习惯了热备份的概念,您几乎拥有完成备份工具包所需的一切。到目前为止,我们讨论过的所有备份类型都具有类似的特征——不足。它们只允许在它们被提取的时间点进行恢复。如果您有两次备份,一次在周一 23:00 完成,第二次在周二 23:00 完成,则您无法恢复到周二 17:00。
还记得本章开头给出的基础设施故障示例吗?现在,让我们更糟,说数据消失了,所有驱动器都出现故障,并且没有复制。该事件发生在周三 21:00。如果没有时间点恢复或 PITR,并且每天在 23:00 进行备份,这意味着您已经不可挽回地丢失了一整天的数据。可以说,使用 XtraBackup 完成的增量备份可以让您稍微减轻这个问题,但它们仍然为数据丢失留下了一些空间,而且经常运行它们不太实际。
MySQL 维护一个名为Binary Log的事务日志。通过将迄今为止我们讨论过的任何备份方法与二进制日志相结合,我们能够以最高事务分辨率恢复到任意时间点。了解备份后需要备份和二进制日志才能使其工作非常重要。您也无法回到过去,因此您无法将数据恢复到创建最早的基本备份或转储之前的时间点。
二进制日志包含时间戳和事务标识符,但您必须依靠事务 ID 进行恢复。不可能告诉 MySQL 恢复到某个时间戳,因此您需要确定最接近该时间戳的事务。当您想恢复到最新的时间点时,这不是问题,但在尝试执行恢复以修复逻辑不一致时可能非常重要和有帮助,就像“部署错误”中的部署错误示例中描述的那样。
MySQL 的一个有趣的特性是它允许 PITR 用于逻辑备份。“从 SQL 转储文件加载数据”部分??讨论使用mysqldump为副本配置存储 binlog 位置。相同的 binlog 位置可以用作 PITR 的起点。与其他数据库不同,MySQL 中的每种备份类型都适用于 PITR。为了便于使用此属性,请确保在进行备份时记下 binlog 位置。一些备份工具会为您做到这一点。当使用那些没有的时候,你可以运行SHOW MASTER STATUS;获取该数据。
二进制日志技术背景
MySQL 与许多其他主流 RDBMS 的不同之处在于它支持“替代存储引擎”中涵盖的多个存储引擎??. 不仅如此,它还支持单个数据库中表的多个存储引擎。这样做的结果是 MySQL 中的某些概念与其他系统不同。
MySQL 中的二进制日志本质上是事务日志。当启用二进制日志时,每个事务(不包括只读事务)都将反映在二进制日志中。有树方法将事务写入二进制日志:
·Statement:在这种模式下,语句按原样记录到二进制日志中,这可能会导致复制场景中的不确定性执行。
·行:在这种模式下,语句被分解为最小的 DML 操作,每个操作修改一个特定的行。尽管它保证了确定性执行,但这种模式是最冗长的,并且会导致最大的文件和 IO 开销。
·混合:在这种模式下,“安全”??语句按原样记录,而其他语句则分解。
通常,事务日志用于崩溃恢复、复制和 PITR。然而,就 MySQL 而言,它的多引擎特性不允许使用 binlog 进行崩溃恢复。每个引擎都维护自己的崩溃恢复机制。例如,MyISAM 不是崩溃安全的,而 InnoDB 有自己的重做日志。MySQL 中的每个事务都是具有两阶段提交的分布式事务,以实现这种多引擎性质。每个提交的事务都保证反映在存储引擎的重做日志中,如果引擎是事务性的,以及在 MySQL 自己的事务日志中:二进制日志。
注意
必须在您的 MySQL 实例中启用二进制日志记录才能使 PITR 成为可能。您还应该默认使用sync_binlog=1 ,以保证每次写入的持久性。请参阅MySQL 文档以了解禁用 binlog 同步的权衡。
我们将在以后更多地讨论二进制日志。
保留二进制日志
要允许时间点恢复,您必须保留从最早备份的二进制日志位置开始的二进制日志。有几种方法可以做到这一点:
·“手动”复制或同步二进制日志??使用一些现成的工具,如rsync 。请记住,MySQL 会继续写入当前的二进制日志文件。如果您正在复制文件而不是持续同步它们,请不要复制当前的二进制日志文件。一旦部分文件变为非当前文件,连续同步文件将通过覆盖部分文件来解决此问题。
·使用mysqlbinlog复制单个文件或连续流式传输binlog。步骤在文档中很容易找到。
·使用 MySQL Enterprise Backup,它具有内置的 binlog 复制功能。请注意,它不是连续复制,而是依赖增量备份来进行 binlog 副本。这允许在两个备份之间进行 PITR。
·通过为binlog_expire_logs_seconds或expire_logs_days变量设置一个较高的值,允许 MySQL 服务器在其数据目录中存储足够的二进制日志。理想情况下不应使用此选项,或者除了上述任何选项之外,还可以使用此选项。如果数据目录发生任何事情,比如文件系统损坏,存储在那里的二进制日志也可能丢失。
确定 PITR 目标
您可以使用 PITR 技术来实现两个目标:
1. 恢复到最新的时间点。
2. 恢复到任意时间点。
第一个,如前所述,对于将完全丢失的数据库恢复到最新的可用状态很有用。第二个对于像以前一样获取数据很有用。这可能有用的一个例子是“部署错误”中给出的部署错误示例??. 要恢复丢失或错误修改的数据,您可以恢复备份,然后将其恢复到执行部署之前的某个时间点。
确定问题发生的实际具体时间可能是一个挑战。通常情况下,找到所需时间点的唯一方法是检查围绕问题时间范围编写的二进制日志。例如,如果您怀疑某个表被删除,您可以查找表名,然后查找任何 DDL,或者专门查找DROP TABLE语句。
让我们举例说明。首先,我们需要实际删除表,我们将删除我们在“从逗号分隔的文件中加载数据”中创建的设施表??. 但是,在此之前,我们将插入一条在原始备份中肯定丢失的记录:
mysql> INSERT INTO facilities(center)
-> VALUES ('this row was not here before');
Query OK, 1 row affected (0.01 sec)
mysql> DROP TABLE nasa.facilities;
Query OK, 0 rows affected (0.02 sec)
我们现在可以返回并恢复我们在本章中所做的一个备份,但是我们会丢失对数据库所做的任何更改,直到DROP 。相反,我们将使用mysqlbinlog命令来检查二进制日志内容并在运行DROP之前找到恢复目标。要查找数据目录中可用的二进制日志列表,您可以运行以下命令:
mysql> SHOW BINARY LOGS;
+---------------+-----------+-----------+
| Log_name | File_size | Encrypted |
+---------------+-----------+-----------+
| binlog.000291 | 156 | No |
| binlog.000292 | 711 | No |
+---------------+-----------+-----------+
2 rows in set (0.00 sec)
警告
MySQL 不会永远将二进制日志保存在其数据目录中。当二进制日志超过binlog_expire_logs_seconds或expire_log_days指定的持续时间时,MySQL 服务器会自动删除它们,也可以通过运行PURGE BINARY LOGS手动删除。如果您想确保二进制日志可用,您应该将它们保存在数据目录之外,如“保存二进制日志”中所述?.
现在二进制日志列表可用,您可以尝试从最后一个到最旧的搜索它们,或者您可以将它们的所有内容一起转储。在我们的示例中,文件很小,因此我们可以采用后一种方法。在任何情况下,都会使用mysqlbinlog命令:
# cd /var/lib/mysql # mysqlbinlog binlog.000291 binlog.000292 \ -vvv --base64-output=decode-rows > /tmp/mybinlog.sql
检查输出文件,我们可以找到有问题的语句:
... #210613 23:32:19 server id 1 end_log_pos 200 ... Rotate to binlog.000291 ... # at 499 #210614 0:46:08 server id 1 end_log_pos 576 ... # original_commit_timestamp=1623620769019544 (2021-06-14 00:46:09.019544 MSK) # immediate_commit_timestamp=1623620769019544 (2021-06-14 00:46:09.019544 MSK) /*!80001 SET @@session.original_commit_timestamp=1623620769019544*//*!*/; /*!80014 SET @@session.original_server_version=80025*//*!*/; /*!80014 SET @@session.immediate_server_version=80025*//*!*/; SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 576 #210614 0:46:08 server id 1 end_log_pos 711 ... Xid = 25 use `nasa`/*!*/; SET TIMESTAMP=1623620768/*!*/; DROP TABLE `facilities` /* generated by server */ /*!*/; SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/; DELIMITER ; ...
我们应该在莫斯科时间 2021-06-14 00:46:09.019544 或二进制日志位置 499 之前停止恢复。我们还需要从最新备份到并包括binlog.00291 的所有二进制日志。使用这些信息,我们可以继续备份恢复和恢复。
示例时间点恢复:XtraBackup
XtraBackup 本身不提供 PITR 功能。您需要添加运行mysqlbinlog的附加步骤,以在恢复的数据库上重放 binlog 内容。
1. 恢复备份。参见“备份和恢复”??确切的步骤。
2. 启动 MySQL 服务器。如果直接在源实例上恢复,建议使用跳过网络选项来防止非本地客户端访问数据库。否则,某些客户端可能会在您实际完成恢复之前更改数据库。
3. 定位备份的二进制日志位置。它在备份目录中的xtrabackup_binlog_info文件中可用。
# cat /tmp/base_backup/xtrabackup_binlog_info
binlog.000291 156
4. 找到您想要恢复到的所需时间戳或二进制日志位置。例如,正如前面所讨论的,在执行DROP TABLE之前。
5. 将二进制日志重放至所需的时间戳。对于此示例,我们单独保留了二进制日志binlog.000291,但您将使用集中式二进制日志存储作为二进制日志的源。使用 mysqlbinlog命令:
# mysqlbinlog /opt/mysql/binlog.000291 \ /opt/mysql/binlog.000292 --start-position=156 \ --stop-datetime="2021-06-14 00:46:00" | mysql
6. 确保恢复成功且数据没有丢失。在我们的例子中,我们将在删除之前查找我们添加到设施表中的记录:
mysql> SELECT center FROM facilities
-> WHERE center LIKE '%before%';
+------------------------------+
| center |
+------------------------------+
| this row was not here before |
+------------------------------+
1 row in set (0.00 sec)
示例时间点恢复:mysqldump
使用mysqldump进行 PITR 所需的步骤类似于之前为 XtraBackup 采取的步骤。我们只是为了完整性而展示这一点,以便您可以看到 PITR 将与 MySQL 中的每个备份类型非常相似。
1. 恢复 SQL 转储。同样,如果您的恢复目标服务器是备份源,您可能希望客户端无法访问它。
2. 从mysqldump备份文件中找到二进制日志位置。
CHANGE MASTER TO MASTER_LOG_FILE='binlog.000010', MASTER_LOG_POS=191098797;
3. 找到您想要恢复到的所需时间戳或二进制日志位置。例如,正如前面所讨论的,在执行DROP TABLE之前。
4. 将二进制日志重放至所需的时间戳。
# mysqlbinlog /path/to/datadir/mysql-bin.000010 \ /path/to/datadir/mysql-bin.000011 \ --start-position=191098797 \ --stop-datetime="20-05-25 13:00:00" | mysql
导出和导入 InnoDB 表空间
物理备份的主要缺点之一是它们通常需要同时复制很大一部分数据库文件。尽管像 MyISAM 这样的存储引擎允许复制空闲表的数据文件,但您不能保证 InnoDB 文件的一致性。但是,在某些情况下,您只需要传输几张表或一张表。到目前为止,我们看到的唯一选择是利用逻辑备份,这可能会慢得令人无法接受。导出和导入表空间功能,正式称为可传输表空间功能,是一种两全其美的方式。为简洁起见,我们还将将此功能称为导出/导入。
可传输表空间功能让您可以将在线物理备份的性能与逻辑备份的粒度相结合。本质上,此功能提供了对 InnoDB 表的数据文件进行在线复制的能力,以用于导入到相同或不同的表中。这样的副本可以作为备份,或作为不同 MySQL 安装之间数据传输的媒体。
当逻辑转储达到同样的目的时,为什么要使用导出/导入?导出/导入要快得多,除了表被锁定之外,不会对服务器产生重大影响。对于进口尤其如此。由于表大小在数 GB 范围内,这是数据传输的少数可行选项之一。
技术背景
为了帮助您理解此功能的工作原理,我们将研究两个概念:一个是表空间,另一个是物理备份。
小结:为了让物理备份保持一致,我们一般可以走两条路线。第一个是关闭实例,或以其他方式以有保证的方式将数据设为只读。二是使数据文件与时间点保持一致,然后累积该时间点到备份结束之间的所有变化。可传输表空间功能以第一种方式工作,需要将表暂时设为只读。
表空间是存储表和索引数据的文件。默认情况下,InnoDB 使用innodb_file_per_table选项,它强制为每个表创建一个专用的表空间文件。但是可以创建一个包含多个表数据的表空间。此外,您可以使用“旧”?? 将所有表驻留在单个ibdata表空间中的行为。仅当每个表使用专用表空间时,默认配置才支持导出。分区表中的每个分区都单独存在表空间,这允许在不同的表之间传输分区或从分区创建表的有趣能力。
导出表空间
既然已经涵盖了这两个概念,您就知道需要为导出做什么。但是,仍然缺少的一件事是表定义。尽管大多数 InnoDB 表空间文件实际上包含其表的数据字典记录的冗余副本,但可传输表空间的当前实现要求在导入之前在目标上存在表。
导出表空间的步骤是:
1. 获取表定义
2. 停止对表(或表)的所有写入并使其保持一致
3. 准备好后面导入表空间所需的额外文件
o .cfg文件存储用于模式验证的元数据
o .cfp文件仅在使用加密时生成,将具有目标服务器解密表空间所需的转换密钥
要获得表定义,您可以使用我们在本书中多次展示的SHOW CREATE TABLE命令。所有其他步骤都由 MySQL 使用单个命令自动完成:FLUSH TABLE ... FOR EXPORT 。该命令锁定表并在目标表的常规.ibd文件附近生成附加文件(或文件,如果使用加密)。让我们从sakila数据库中导出actor表:
mysql> USE sakila
mysql> FLUSH TABLE actor FOR EXPORT;
Query OK, 0 rows affected (0.00 sec)
执行FLUSH TABLE的会话应该保持打开状态,因为一旦会话终止,actor表就会被释放。一个新文件actor.cfg应该出现在 MySQL 数据目录下的常规actor.ibd附近。我们来验证一下:
# ls -1 /var/lib/mysql/sakila/actor.*
/var/lib/mysql/sakila/actor.cfg /var/lib/mysql/sakila/actor.ibd
这对.ibd和.cfg文件现在可以复制到某个地方并在以后使用。复制文件后,通常建议通过运行UNLOCK TABLES语句或关闭调用FLUSH TABLE的会话来释放表上的锁。完成所有这些后,您就有了一个可以导入的表空间。
注意
分区表具有多个文件,每个文件都有一个专用
learning_mysql_partitioned#p#p0.cfg learning_mysql_partitioned#p#p0.ibd learning_mysql_partitioned#p#p1.cfg learning_mysql_partitioned#p#p1.ibd
导入表空间
导入表空间非常简单。它由以下步骤组成:
1. 使用保留的定义创建一个表。无法以任何方式更改表的定义。
2. 丢弃表的表空间。
3. 复制.ibd和.cfg文件。
4. 修改 表以导入表空间。
如果该表存在于目标服务器上并且具有相同的定义,则无需执行步骤 1。
让我们在同一台服务器上的另一个数据库中恢复actor表。该表需要存在:
mysql> USE nasa
mysql> CREATE TABLE `actor` (
-> `actor_id` smallint unsigned NOT NULL AUTO_INCREMENT,
-> `first_name` varchar(45) NOT NULL,
-> `last_name` varchar(45) NOT NULL,
-> `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
-> ON UPDATE CURRENT_TIMESTAMP,
-> PRIMARY KEY (`actor_id`),
-> KEY `idx_actor_last_name` (`last_name`)
-> ) ENGINE=InnoDB AUTO_INCREMENT=201 DEFAULT
-> CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
Query OK, 0 rows affected (0.04 sec)
只要演员在创建表时,MySQL创建的.ibd它的文件:
# ls /var/lib/mysql/nasa/
actor.ibd facilities.ibd
这将我们带到下一步:丢弃这个新表的表空间。这是通过运行一个特殊的ALTER TABLE 来完成的:
mysql> ALTER TABLE actor DISCARD TABLESPACE;
Query OK, 0 rows affected (0.02 sec)
和的.ibd文件将会消失:
# ls /var/lib/mysql/nasa/
facilities.ibd
警告
丢弃表空间会导致相关表空间文件的完全删除,并且不是可恢复的操作。如果您意外运行ALTER TABLE ... DISCARD TABLESPACE,您将需要从备份中恢复。
我们现在可以将原始演员表的导出表空间与.cfg文件一起复制:
# cp -vip /opt/mysql/actor. /var/lib/mysql/nasa/*
'/opt/mysql/actor.cfg' -> '/var/lib/mysql/nasa/actor.cfg' '/opt/mysql/actor.ibd' -> '/var/lib/mysql/nasa/actor.ibd'
完成所有步骤后,现在可以导入表空间并验证数据:
mysql> ALTER TABLE actor IMPORT TABLESPACE;
Query OK, 0 rows affected (0.02 sec)
mysql> SELECT * FROM nasa.actor LIMIT 5;
+----------+------------+--------------+---------------------+
| actor_id | first_name | last_name | last_update |
+----------+------------+--------------+---------------------+
| 1 | PENELOPE | GUINESS | 2006-02-15 04:34:33 |
| 2 | NICK | WAHLBERG | 2006-02-15 04:34:33 |
| 3 | ED | CHASE | 2006-02-15 04:34:33 |
| 4 | JENNIFER | DAVIS | 2006-02-15 04:34:33 |
| 5 | JOHNNY | LOLLOBRIGIDA | 2006-02-15 04:34:33 |
+----------+------------+--------------+---------------------+
5 rows in set (0.00 sec)
你可以看到我们在nasa.actor 中有来自sakila.actor的数据。
可传输表空间的最大优点可能是它们的效率。您可以使用此功能轻松地在数据库之间移动非常大的表。
XtraBackup 单表还原
也许令人惊讶的是,我们将在可传输表空间的上下文中再次提及 XtraBackup。这是因为 XtraBackup 允许从任何现有备份中导出表。事实上,这是恢复单个表最方便的方法,也是单表或部分数据库 PITR 的第一个构建块。
此功能完全基于可传输表空间,并且具有所有限制。例如,它不适用于非文件每表表空间。
要执行单表还原,您应该首先使用--export命令行参数运行xtrabackup以准备要导出的表。您可能会注意到没有指定表的名称,实际上每个表都将被导出。让我们在我们之前进行的备份之一上运行该命令:
# xtrabackup --prepare --export --target-dir=/tmp/base_backup # ls -1 /tmp/base_backup/sakila/
actor.cfg actor.ibd address.cfg address.ibd category.cfg category.ibd ...
您可以看到我们为每个表创建了一个.cfg文件:每个表空间现在都已准备好在另一个数据库中传输和导入。从这里,您可以重复“导入表空间”中的步骤??从其中一个表中恢复数据。
最先进的备份和恢复技术之一是基于可传输表空间的顶部。即单表或部分数据库时间点恢复。我们没有给出确切的步骤,只是介绍了这项技术,以便您知道这是可能的。
单表或部分 PITR 很棘手,这对于大多数数据库管理系统来说都是如此。正如您之前在“时间点恢复”中看到的那样??,MySQL中的PITR是基于binlog的。这对于部分恢复意味着记录涉及所有数据库中所有表的事务,但在通过复制应用时可以过滤二进制日志。因此,非常简单,部分恢复过程是:导出所需的表,构建一个完全独立的实例,并通过复制通道为其提供二进制日志。
您可以在社区博客和文章中找到更多信息,例如“ MySQL 单表 PITR ”、“使用 MySQL 过滤二进制日志”和“如何使 MySQL PITR 更快”。
在某些情况下正确使用导出和导入表空间功能是一种强大的技术。
测试和验证备份
只有当您确定可以信任备份时,备份才会有用。有很多例子说明人们的备份系统在最需要的时候出现故障。完全有可能经常进行备份而仍然丢失数据。
备份可能出错或失败的方式有多种:
·不一致的备份:最简单的例子是在数据库运行时从多个卷错误地获取快照备份。不幸的是,某些备份甚至可能是一致的,或者至少不会破坏到足以让您注意到的程度,直到为时已晚。备份可能损坏或丢失数据。
·源数据库损坏:正如我们广泛讨论的那样,物理备份将拥有所有数据库页面的副本,无论是否损坏。一些工具尝试在数据运行时验证数据,但这并非完全没有错误。您成功的备份可能包含以后无法读取的错误数据。
·备份损坏:备份本身只是数据,因此容易受到与原始数据相同的问题的影响。如果数据在存储时损坏,您成功的备份可能最终完全无用。
·错误:事情发生。您已经使用了十几年的备份工具可能有一个错误,所有人都会遇到。在最好的情况下,您的备份将失败;在最坏的情况下,它可能无法恢复。
·操作错误:我们都是人,也会犯错误。如果您将一切都自动化,那么这将从人为错误变为错误。
这不是您可能面临的问题的完整列表,但它可以让您深入了解即使您的备份策略是合理的也可能面临的问题。让我们回顾一些可以让您睡得更好的步骤:
·无论何时实施备份系统,都要对其进行彻底的测试,并在各种模式下进行测试。确保您可以备份系统,并使用备份进行恢复。测试有负载和无负载。当没有连接修改数据时,备份可以是一致的,如果不是这样,则备份失败。
· 同时使用物理和逻辑备份。它们具有不同的属性和故障模式,尤其是在源数据损坏方面。
·备份您的备份,或确保它们至少与数据库一样持久。
·最后,定期进行备份恢复测试。
最后一点特别有趣。在恢复和测试之前,没有备份是安全的。这意味着,在完美的世界中,您的自动化实际上会尝试使用备份来构建数据库服务器,并且仅在运行良好时才报告成功。此外,该新数据库可以作为副本附加到源,并且可以使用Percona Toolkit 中的pt-table-checksum等数据验证工具来检查数据一致性。
以下是物理备份的备份数据验证的一些可能步骤:
1. 准备备份。
2. 恢复备份。
3. 对所有*.ibd文件运行innochecksum 。
以下命令将在 Linux 上并行运行四个innochecksum进程:
$ find . -type f -name "*.ibd" -print0 |\ xargs -t -0r -n1 --max-procs=4 innochecksum
4. 使用恢复的备份启动一个新的 MySQL 实例。使用备用服务器,或仅使用专用的.cnf文件,并且不要忘记使用非默认端口和路径。
5. 使用mysqldump或任何替代方法来转储所有数据,确保它是可读的,并提供另一个备份副本。
6. 将新 MySQL 实例作为副本附加到原始源数据库,并使用pt-table-checksum或任何替代方法验证数据是否匹配。该过程在xtrabackup文档以及其他来源中有很好的解释。
这些步骤很复杂,可能需要很长时间,因此您应该决定是否适用于您的业务和环境来利用所有这些步骤。
数据库备份策略入门
现在我们有很多与备份和恢复相关的零碎内容,我们可以拼凑出一个非常强大的备份策略。让我们从头开始构建它。
时间点恢复
我们需要决定是否需要 PITR 功能,因为这将推动我们做出有关备份策略的决策。您必须针对您的具体情况做出决定,但我们的建议是默认使用 PITR。它可以成为救命稻草。如果我们决定需要这个功能,我们需要设置二进制日志和二进制日志复制。
逻辑备份
我们可能需要逻辑备份,无论是为了它们的可移植性还是为了防止损坏。由于逻辑备份会显着加重源数据库负载,因此将它们安排在负载最小的时间。由于时间或负载限制,或两者兼而有之,有时可能无法从生产数据库进行逻辑备份。由于我们仍然希望能够运行逻辑备份,我们可以使用以下技术:
·在复制的数据库上运行逻辑备份。在这种情况下跟踪 binlog 位置可能会出现问题,因此在这种情况下建议使用基于 GTID 的复制。
·将逻辑备份的创建合并到物理备份的验证过程中。准备好的备份是一个数据目录,可以立即被 MySQL 服务器使用。如果您运行一个以备份为目标的服务器,您将破坏该备份,因此您需要先将准备好的备份复制到某处。
物理备份
根据操作系统、MySQL 风格、系统属性和对文档的仔细审查,我们需要选择我们将用于物理备份的工具。为简单起见,我们在这里选择 XtraBackup。
要做的第一个决定是 MTTR(平均恢复时间)目标对我们的重要性。例如,如果您只进行每周基本备份,您可能最终需要应用几乎一周的事务来恢复该备份。要降低 MTTR,请每天甚至每小时实施增量备份。
退一步说,您的系统可能太大了,即使使用其中一种物理备份工具进行热备份也不适合您。在这种情况下,如果可能,您需要获取卷的快照。
备份存储
我们需要确保我们的备份是安全的,最好是冗余存储。这可能是一种硬件存储设置,使用性能较低但冗余的 5 级或 6 级 RAID 阵列。这可能是一种不太可靠的存储,但我们将向云存储添加连续的备份流,例如Amazon 的对象存储——S3——或其他替代方案。最后,如果我们可以选择备份工具,我们可能会默认使用 S3。
备份测试验证
最后,一旦我们有了备份,我们就会完美地建立一个备份测试过程。根据可用于实施和维护此演习的预算,我们应该决定每次或偶尔运行多少步骤。
通过实施这些步骤,我们可以说我们已经覆盖了我们的基础,并且我们的数据库得到了安全的备份。有时可能感觉我们从未使用过备份,但您必须记住,您最终将面临灾难——这只是时间问题。