如何使用LVM快照将MySQL数据库备份到DigitalOcean空间
介绍
定期数据库备份是防止意外数据丢失事件的关键步骤。 设计有效的备份和恢复策略通常涉及在性能影响、实施成本和数据存储成本与恢复速度、数据完整性和备份覆盖率之间进行权衡。 最佳解决方案将取决于您的恢复点和时间 目标 以及数据库规模和架构。
在本指南中,我们将演示如何使用 LVM 快照对正在运行的 MySQL 数据库执行实时(或“热”)物理备份。 然后,我们将压缩数据并将其存储在 DigitalOcean Space 中。
本教程中介绍的过程非常适合大型 MySQL 数据库、使用混合存储引擎(如 InnoDB、TokuDB 和 MyISAM)的数据库,以及附加了多个块存储卷并使用 LVM 管理的数据库服务器。
我们将首先确保我们的 Ubuntu 16.04 服务器可以拍摄和挂载 LVM 快照。 接下来,我们将拍摄包含 MySQL 数据目录的逻辑卷的 LVM 快照。 然后我们将挂载这个快照卷(冻结的逻辑卷),并将 MySQL 数据目录压缩并传送到 DigitalOcean Spaces 进行存储。 最后,我们将简要介绍一个示例恢复场景。
先决条件
要使用本指南,您需要满足以下先决条件:
- 具有 sudo 权限的非 root 用户的 Ubuntu 16.04 Droplet,详见 使用 Ubuntu 16.04 的初始服务器设置
- 正在运行的 MySQL 5.7+ 安装,详见 How To Install MySQL on Ubuntu 16.04
- 用于存储 MySQL 数据库数据目录的 LVM 逻辑卷:
- 要了解有关 LVM 以及如何设置逻辑卷的更多信息,请参阅 LVM 概念、术语和操作简介
- 要了解有关将 MySQL 的数据目录从其默认
/var/lib/mysql
位置移动的更多信息,请参阅 如何在 Ubuntu 16.04 上将 MySQL 数据目录移动到新位置
- DigitalOcean Space 和一组 API 凭证,详见 如何创建 DigitalOcean Space 和 API 密钥。
s3cmd
命令行文件传输客户端 (2.X) 已安装,详见 如何使用 Logrotate 和 S3cmd 在 Ubuntu 16.04 上将日志归档到对象存储的步骤 1s3cmd
配置为访问您的空间,详见 如何配置 s3cmd 2.x 以管理 DigitalOcean 空间
完成所有这些设置后,您就可以开始阅读本指南了。
第 1 步 — 调查 MySQL 和 LVM 配置
首先,我们将找到我们的 MySQL 数据目录并记下有关我们的 LVM 配置的详细信息。
定位 MySQL datadir
要查找 MySQL 数据目录的路径,请运行以下命令:
mysqladmin -u root -p variables | grep datadir
出现提示时输入您的 MySQL root
密码。 您应该会看到类似于以下内容的输出:
Output| datadir | /data/mysql/
对于本指南中使用的 MySQL 安装,数据目录为 /data/mysql
。
我们现在需要确认 /data/mysql
位于 LVM 逻辑卷上。 为了确认这一点,我们将运行 lsblk
:
lsblk
您应该会看到类似于以下内容的输出:
OutputNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 600G 0 disk └─vg1-mysql_data 252:0 0 475G 0 lvm /data vda 253:0 0 160G 0 disk ├─vda1 253:1 0 159.9G 0 part / ├─vda14 253:14 0 4M 0 part └─vda15 253:15 0 106M 0 part /boot/efi
由此我们观察到 /data
实际上是名为 mysql_data
的 LVM 逻辑卷的挂载点。 它是卷组 vg1
的成员。
我们现在需要确保我们的卷组 vg1
中有足够的可用空间来拍摄 LVM 快照。
探索 LVM 配置
请务必注意,本节中描述的命令的输出将根据服务器的硬件和 LVM 配置而有所不同。 让我们快速研究一下本指南中使用的 Ubuntu 16.04 服务器的硬件和 LVM 配置。
首先,让我们看看使用 pvscan
有多少物理卷:
sudo pvscan
您应该会看到类似于以下内容的输出:
Output PV /dev/sda VG vg1 lvm2 [500.00 GiB / 25.00 GiB free] Total: 1 [500.00 GiB] / in use: 1 [500.00 GiB] / in no VG: 0 [0 ]
我们观察到我们有一个 500GB 的物理卷 (/dev/sda
),它位于一个卷组 (vg1
) 中。 此物理卷的 475GB 已分配给逻辑卷,而 25GB 仍可供卷组使用。
我们可以通过使用 vgdisplay
命令更深入地查看 vg1
卷组来确认这一点:
sudo vgdisplay
您应该看到类似于以下内容的输出:
Output--- Volume group --- VG Name vg1 System ID Format lvm2 Metadata Areas 1 Metadata Sequence No 2 VG Access read/write VG Status resizable MAX LV 0 Cur LV 1 Open LV 1 Max PV 0 Cur PV 1 Act PV 1 VG Size 500.00 GiB PE Size 4.00 MiB Total PE 127999 Alloc PE / Size 121600 / 475.00 GiB Free PE / Size 6399 / 25.00 GiB VG UUID KEsoDE-zON7-NdyO-ioxb-6FSl-CB4m-S3QCRj
从 Alloc PE / Size 和 Free PE / Size 行中,我们观察到在 vg1
卷组中分配了 475GB 和 25GB 空闲空间。 Cur PV 行显示我们在这个卷组中有 1 个物理卷。 Cur LV 行表明我们已使用此卷组中的空间池来创建 1 个逻辑卷。
现在让我们使用 lvdisplay
来看看这个逻辑卷:
sudo lvdisplay
您应该会看到类似于以下内容的输出:
Output --- Logical volume --- LV Path /dev/vg1/mysql_data LV Name mysql_data VG Name vg1 LV UUID T98x9c-zvC1-f0Rw-4ipn-Cxo2-duwk-KUwQQc LV Write Access read/write LV Creation host, time LVM, 2018-04-18 20:11:48 +0000 LV Status available # open 1 LV Size 475.00 GiB Current LE 121600 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 252:0
从 LV Size 我们看到我们有一个 475GB 的逻辑卷,mysql_data
,在 /dev/vg1/mysql_data
找到(回想 vg1
是 mysql_data
的卷组)。
总而言之,在本教程使用的 Ubuntu 16.04 服务器上,我们有一个 500GB 物理卷 (/dev/sda
) 用于支持一个卷组 (vg1
),我们从中创建了一个475GB 逻辑卷 (mysql_data
)。 这会在卷组中留下 25GB 的可用空间,可用于创建更多逻辑卷(和快照)。
您的硬件和 LVM 配置可能会有所不同; 您可能连接了多个块存储设备,汇集到单个或多个卷组中。 然而,为给定逻辑卷拍摄快照的过程将是相同的。
使用本节介绍的一系列命令,您现在应该对 LVM 和硬件配置有一个大致的了解。
在下一步中,我们将为您的数据库服务器准备 LVM 快照。
第 2 步 — 为 LVM 快照准备您的服务器
为了确保我们可以安全地拍摄 LVM 快照,我们需要提供足够的磁盘空间来覆盖在备份和文件传输到 Spaces 期间可能发生的任何写入或更改。 根据您的数据库的大小,此备份可能需要几个小时才能完成,因此最好谨慎行事。 如果您的快照卷在执行备份时空间不足,则快照卷将失效,您将不再拥有一致的备份。
在上一步中,我们观察到包含我们的主逻辑卷 (mysql_data
) 的卷组 (vg1
) 只有 25GB 可用空间。 尽管在备份我们的数据库所需的时间内可能不会将 25GB 的更改写入磁盘,但理想情况下,我们希望至少有 100GB 的安全边际。 在生产环境中,最好的做法是测量计划备份窗口期间写入磁盘的平均数据量,并相应地缩放快照卷的大小。
要向 vg1
卷组添加额外的 75GB 空间,我们可以附加块存储设备,或者增加当前附加到 Droplet 的卷的大小。 在本教程中,我们将扩展已附加的块存储卷; 要了解有关附加块存储卷的更多信息,您可以参考 DigitalOcean 块存储简介。
注意: 部分地区尚不支持 Block Storage,您可能无法将 Block Storage 卷附加到您的 Droplet。 在这种情况下,一个合理的解决方法是对您的 Droplet 进行快照并使用此快照图像创建一个新的 Droplet,然后您可以向其中添加块存储。
让我们扩展附加到这个 Droplet 的块存储卷。
导航到 DigitalOcean 的 Web 控制面板,然后从仪表板导航到您的 Droplet。
在侧边栏中,单击 Volumes:
在此窗格中,您应该看到附加到您的 Droplet 的任何块存储卷。 对于本指南中使用的 Ubuntu Droplet,我们有一个附加的块存储卷:
单击更多,然后单击调整音量。
从这里,您可以选择几个预定义的卷大小之一,或选择您自己的卷大小。 让我们将 500GB 的卷增加 100GB 到 600GB:
按 继续 。 您的附加块存储卷现在增加了 100GB。
要将此设备更改传播到 LVM,我们需要运行 pvresize
。
登录到您的服务器,然后再次运行 pvscan
以扫描物理卷:
sudo pvscan
对于我们的 /dev/sda
物理卷,您应该看到与之前相同的输出:
Output PV /dev/sda VG vg1 lvm2 [500.00 GiB / 25.00 GiB free] Total: 1 [500.00 GiB] / in use: 1 [500.00 GiB] / in no VG: 0 [0 ]
现在,在卷上运行 pvresize
以填充我们刚刚添加的额外空间:
sudo pvresize /dev/sda
您应该看到以下输出:
OutputPhysical volume "/dev/sda" changed 1 physical volume(s) resized / 0 physical volume(s) not resized
让我们通过运行另一个 pvscan
来确认我们的物理卷现在大了 100GB:
sudo pvscan
我们观察到 /dev/sda
物理卷现在是 600GB:
Output PV /dev/sda VG vg1 lvm2 [600.00 GiB / 125.00 GiB free] Total: 1 [600.00 GiB] / in use: 1 [600.00 GiB] / in no VG: 0 [0 ]
现在让我们确认我们的卷组的可用空间也增加了 100GB:
sudo vgdisplay
然后,您应该会看到以下输出:
Output --- Volume group --- VG Name vg1 System ID Format lvm2 Metadata Areas 1 Metadata Sequence No 3 VG Access read/write VG Status resizable MAX LV 0 Cur LV 1 Open LV 1 Max PV 0 Cur PV 1 Act PV 1 VG Size 600.00 GiB PE Size 4.00 MiB Total PE 153599 Alloc PE / Size 121600 / 475.00 GiB Free PE / Size 31999 / 125.00 GiB VG UUID KEsoDE-zON7-NdyO-ioxb-6FSl-CB4m-S3QCRj
这表明我们现在有 125GB 的可用空间来创建我们的快照卷。
就本教程而言,125GB 足以在备份和上传过程中吸收写入和更改,但在生产设置中,快照卷大小应与备份窗口期间的预期磁盘使用量成比例缩放。
现在我们的卷组中有足够的可用空间来覆盖快照和备份期间可能发生的任何写入或更改,我们可以继续创建快照卷。
第 3 步 — 创建和挂载 LVM 快照
警告: 当 LVM 快照处于活动状态时,写入磁盘时会出现一些性能下降。 您应该首先使用具有模拟负载的非生产数据库测试此过程,以验证此方法是否适用于您的生产部署。
我们现在将使用 lvcreate
创建 mysql_data
逻辑卷的快照。 在我们这样做之前,我们需要使用 FLUSH TABLES WITH READ LOCK
冻结对数据库的写入,以便我们可以保证数据的一致性。 这些表只需要在我们运行 lvcreate
之前被读锁定,此时它们可以被解锁。 如果您编写这一系列命令的脚本,则总锁定时间应该非常短,具体取决于当前执行的写入查询。
读锁 MySQL 数据库
让我们从刷新表开始。 从您的数据库服务器上的终端,使用 mysql
登录您的 MySQL 数据库:
mysql -u root -p
在 MySQL shell 中,运行 FLUSH TABLES
命令以读取锁定您的数据库。
警告: 运行以下命令后,所有打开的表将被关闭,所有数据库的所有表都将被全局读锁锁定。 如果在生产数据库上运行此命令,最佳实践是在副本上执行此命令或作为脚本的一部分,以最大程度地减少数据库锁定的时间。
FLUSH TABLES WITH READ LOCK;
您应该看到以下输出:
OutputQuery OK, 0 rows affected (0.00 sec)
这表明您的数据库已被读锁定。 不要退出 MySQL 提示,我们需要让它保持打开状态。
我们现在将创建并挂载用于存放 MySQL 数据的逻辑卷的 LVM 快照。
- 创建和挂载快照卷
保持此 MySQL 客户端连接打开,从新的终端窗口登录到您的数据库服务器。
警告: 如果关闭此连接,锁将被丢弃并恢复写入,导致快照不一致。
我们现在可以拍摄 mysql_data
逻辑卷的快照。 在执行物理备份时,我们将分配 100GB 的缓冲区空间来吸收写入和其他更改。 要创建 LVM 快照,请运行以下 lvcreate
命令:
sudo lvcreate -L 100G -s -n mysql_data_snap /dev/vg1/mysql_data
-L
标志指定逻辑卷的大小,在本例中为 100GB。 -s
表示逻辑卷将是快照,在本例中为 /dev/vg1/mysql_data
逻辑卷。 我们选择将此快照卷命名为 mysql_data_snap
。
您应该看到以下结果:
OutputLogical volume "mysql_data_snap" created.
这表明我们现在拥有 mysql_data
逻辑卷的副本,我们可以从中执行备份。
现在我们基本上已经在某个时间点“冻结”了我们的 MySQL 数据文件,我们可以解锁我们的数据库表并恢复写入。 从您打开的 MySQL 连接中,运行以下命令:
UNLOCK TABLES;
您应该看到以下结果:
OutputQuery OK, 0 rows affected (0.00 sec)
表已解锁,您现在可以安全地关闭此连接。
此时,您的数据库仍然处于活动状态并接受传入的连接和写入,但是我们在运行 FLUSH TABLES WITH READ LOCK
的时间点(或者完全准确地说,时间点)拥有一致的数据快照FLUSH
后的最后一次写入查询完成时)。
最后一步是挂载这个快照,以便我们可以访问这些冻结的数据文件。
首先,我们将创建一个名为 /backup_src
的挂载点:
sudo mkdir /backup_src
现在,我们将快照卷挂载到 /backup_src
:
sudo mount /dev/vg1/mysql_data_snap /backup_src
我们现在可以访问冻结的数据文件。 让我们来看看:
cd /backup_src ls
你应该看到你的 MySQL 数据目录:
Outputlost+found mysql
现在我们可以访问数据的一致快照,我们可以将其备份到 DigitalOcean Space。
第 4 步 — 压缩文件并将其上传到 DigitalOcean Spaces
要将此备份上传到我们的 DigitalOcean Space,我们将使用我们在 先决条件步骤 中安装和配置的 s3cmd
工具。
我们将首先测试我们的 s3cmd
配置并尝试访问我们的备份空间(在本教程中,我们的空间被命名为 mysql-backup-demo
):
s3cmd info s3://mysql-backup-demo/
您应该看到以下输出:
Outputs3://mysql-backup-demo/ (bucket): Location: nyc3 Payer: BucketOwner Expiration Rule: none Policy: none CORS: none ACL: 3587522: FULL_CONTROL
此输出表示连接成功,并且 s3cmd
可以将对象传输到空间。
我们现在将我们的 MySQL 数据目录压缩并上传到 mysql-backup-demo
空间:
sudo tar -czvf - /backup_src/mysql | s3cmd put - s3://mysql-backup-demo/mysql_backup_180423.tar.gz
在这里,我们使用 tar
来压缩和存档 MySQL 数据目录,并将输出通过管道传输到 s3cmd
,我们使用它来将压缩的存档传输到 Spaces。 我们将压缩存档命名为 mysql_backup_180423.tar.gz
。
由于我们在详细模式下使用了 tar
,您将看到正在压缩的文件列表(要隐藏此输出,请省略上述命令中的 -v
标志)。
输出将以以下文件传输信息结束:
Output... upload: '<stdin>' -> 's3://mysql-backup-demo/mysql_backup_180423.tar.gz' [part 1, 1417kB] 1451996 of 1451996 100% in 0s 1993.41 kB/s done
传输完成后,我们将通过列出空间内容来验证文件是否已成功传输到我们的空间:
s3cmd ls s3://mysql-backup-demo/
您应该看到备份存档文件:
Output2018-04-23 20:39 297 s3://mysql-backup-demo/mysql_backup_180423.tar.gz
至此,我们已经成功完成了对 DigitalOcean Spaces 的物理 MySQL 备份。
我们现在将卸载并删除快照卷,将已用空间恢复到我们的卷组 vg1
。
第 5 步 — 卸载和删除快照卷
现在我们的数据已经备份,我们不再使用我们在本教程前面创建的快照卷,可以安全地删除它。
要卸载卷,请运行以下命令:
sudo umount /backup_src
将 /backup_src
替换为您的快照卷的挂载点。
我们现在可以删除快照卷。 为此,请运行以下命令:
sudo lvremove vg1/mysql_data_snap
这里,vg1
对应您的卷组名称,mysql_data_snap
对应您的快照卷名称。
系统将提示您确认删除,您应回复 Y。
您应该看到以下输出:
Output Logical volume "mysql_data_snap" successfully removed
快照卷已成功删除。 您现在已经完成了完整的 MySQL 物理备份并将其上传到您的 DigitalOcean Space。
我们将通过快速运行恢复方案来结束本教程。
第 6 步 — 从物理备份测试恢复
为了从我们之前上传到 Spaces 的物理备份中恢复我们的 MySQL 数据库,我们将备份传输到我们的数据库服务器,然后使用提取的文件作为我们恢复的 MySQL 数据目录。
让我们首先将备份从我们的空间传输回数据库服务器上用户的主目录:
s3cmd get s3://mysql-backup-demo/mysql_backup_180423.tar.gz ~/mysql_backup_180423.tar.gz
您应该看到一些文件传输输出:
Outputdownload: 's3://mysql-backup-demo/mysql_backup_180423.tar.gz' -> '~/mysql_backup_180423.tar.gz' [1 of 1] 1451889 of 1451889 100% in 0s 38.49 MB/s done
我们现在将停止正在运行的数据库服务器并清除现有数据目录,因为我们想测试从物理备份文件的干净还原。
首先,停止 MySQL 服务器:
sudo service mysql stop
现在,删除 MySQL 数据目录的内容:
sudo rm -rf /data/*
回想一下,在本教程中,非默认 MySQL 数据目录路径是 /data
。
现在,将物理备份存档解压缩到您的 MySQL 数据目录:
sudo tar -xzvf ~/mysql_backup_180423.tar.gz -C /data
现在数据文件已经恢复,我们可以重新启动 MySQL 数据库并让它恢复:
sudo service mysql start
最后,我们可以登录到我们的数据库服务器来验证还原是否成功完成:
mysql -u root -p
输入密码后,您应该会看到 MySQL 客户端提示:
OutputWelcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 4 Server version: 5.7.21-0ubuntu0.16.04.1 (Ubuntu) Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
从这里您可以扫描一些表以验证您的数据是否完整。
结论
在本教程中,我们演示了如何利用 LVM 的快照功能来冻结文件系统并对正在运行的 MySQL 实例执行完整的物理备份和恢复。 如果您使用 LVM 来管理一个或多个包含 MySQL 数据的存储卷,则此功能提供了一种方便的方法来备份您的生产数据库。
在生产环境中,理想情况下,此过程应编写脚本并安排适当的日志记录、监控和警报。 此外,不应在主服务器上运行 FLUSH TABLES WITH READ LOCK
(无论多么简短),而应在负载最小的副本上运行。 请注意,稍作修改,您还可以调整上述过程以从主物理备份快速启动副本。
如果您的 MySQL 实例专门使用 InnoDB 作为其存储引擎,您还可以使用 Percona XtraBackup 以类似的方式执行数据库的物理备份。 要了解更多信息,请参阅我们关于 如何在 Ubuntu 16.04 上使用 Percona 将 MySQL 数据库备份到对象存储的教程。
将物理备份文件上传到 Spaces 的合理替代方法是将 LVM 快照与 Droplet 快照结合使用。 要了解有关 Droplet 快照的更多信息,请参阅 DigitalOcean 备份和快照说明 。
要了解有关本指南中使用的对象存储 DigitalOcean Spaces 的更多信息,请参阅 DigitalOcean Spaces 简介。