使用 zbackup 的理想备份
数据在容量和重要性上都在增长。随着时间的推移,我们需要存储的数据量正在增长,而且数据本身对于组织而言正变得越来越关键。能够快速可靠地备份和恢复这些信息变得越来越重要。使用基于云的系统可以将数据分散到多个服务器和位置。
在我工作的地方,数据已经从单个服务器上的不到 1GB 增长到分布在多个数据中心的 30 多台服务器上的 500GB 以上。像 Distribute IT 和 Code Spaces 事件这样的灾难表明,无效的备份实践可能会摧毁蓬勃发展的业务。企业级备份解决方案通常成本高昂,但我们创建备份解决方案所需的工具存在于开源社区中。
zbackup 救援在切换了许多不同的备份策略之后,我找到了一个接近理想的备份解决方案,以满足我们特定的用例。这包括定期备份具有大量文件以及非常大的文件的多台机器,并且能够恢复以前制作的任何备份。
该解决方案结合了 zbackup、rsync 和 LVM 快照。zbackup 的工作原理是对流(例如,tar 或数据库备份)进行重复数据删除,并将块存储到存储池中。如果再次遇到相同的块,则会重复使用之前的块。
结合这三个要素,我们得到一个提供以下功能的解决方案
-
多个版本:我们可以每小时存储系统的完整快照,重复数据删除意味着每个新备份的增量存储成本可以忽略不计。
-
存储非常大的文件:数据库备份可能非常大,但差异很小,不是块对齐的(想象一下在文件开头插入一个字节)。字节级重复数据删除意味着我们只存储版本之间的更改,类似于执行 diff。
-
存储许多小文件:备份数百万个文件会产生更少数量的重复数据删除块,这些块可以更轻松地管理。
-
轻松在磁盘之间和 WAN 上复制:存储池中的文件是不可变的;新块存储为新文件。这使得将它们 rsync 到其他驱动器或机器非常快速和高效。这也意味着我们可以将它们同步到几乎任何类型的机器或文件存储。
-
压缩:压缩文件可以显着减小大小,但使用它通常会阻止 rsync 或重复数据删除工作。zbackup 在重复数据删除后压缩块,因此 rsync 仍然高效。如前所述,只需要 rsync 新块。
-
快速备份:首次备份后的备份以接近磁盘读取速度的速度完成。更重要的是,通过在每台服务器上运行 zbackup,大部分 CPU 和 I/O 负载是分散的。这意味着中央服务器上所需的 CPU 或 I/O 最少,并且仅传输重复数据删除的块,从而提供可扩展性。
-
高度冗余:通过同步到外部驱动器和其他服务器,即使备份损坏或销毁,我们也能够恢复我们的信息。
有很多替代方案可以替代使用 zbackup。我在下面比较了一些选项
-
磁带:成本相对较高,并且读取和写入需要很长时间,因为整个备份都被写入。对于存档存储来说,这是一个不错的选择,但它不适合频繁快照,因为您无法每小时写入 500GB 的磁带。
-
rsnapshot:无法以任何合理的方式处理大文件中的小更改,因为每个新版本都会保留一个新副本。当复制和删除大量文件时,对中央备份服务器造成巨大的 I/O 负载。将硬链接同步到另一个设备或机器也很慢。
-
Tarsnap:这是一个优秀的产品,价格非常合理。恢复速度慢以及依赖第三方进行存储使其成为一个不错的后备选项,但可能不适合作为您唯一的备份方法。
-
Git:无法有效处理大文件(或者在某些情况下完全失败)。它也不容易处理其中包含 Git 控制文件的任何内容,因此备份您的 Git 存储库成为一个真正的挑战。由于 Git 在处理大文件方面如此糟糕,因此 tar 目录和使用 tar 文件是不可行的。
-
ZFS/BTRFS:文件系统快照非常快速,并且适用于小文件。即使文件中最小的更改也需要重新复制文件(如果启用了重复数据删除,对于 ZFS 来说这并非完全正确;但是,这会产生显着的内存负载,并且仅当文件的大部分块未更改时才有效,例如 Mbox 文件或数据库后备存储)。
-
Duplicity:这似乎类似于 zbackup,并且具有许多相同的优势,除了在具有不同名称的文件之间进行重复数据删除。虽然它已经处于 beta 阶段很长时间了,但它似乎具有许多支持远程后端的特性,而 zbackup 只是一个重复数据删除块存储。
此方法的关键部分是在步骤 1 中使用 zbackup。与其他备份格式相比,zbackup 生成的备份具有非凡的属性,如前所述,因此其余步骤可以根据您需要的可用性和持久性级别进行定制。
-
每个虚拟机服务器都使用 zbackup 备份到本地重复数据删除块存储。这意味着如果需要,每个快照都可以在本地使用。
-
然后将 zbackup 存储复制到中央备份服务器,以便在需要时可以恢复。
-
中央服务器上的 zbackup 存储被复制到其他服务器。
-
备份也同步到外部存储——例如,USB 驱动器。我们在驱动器之间轮换,以便驱动器保持异地状态,以防发生灾难或备份损坏。
-
最后,我们对 zbackup 存储所在的文件系统进行快照。
zbackup 完全符合 UNIX 哲学。它做了两件看似简单的事情,使其行为几乎像一个文件。首先是获取传递给 stdin 的数据流并将其写入块存储。数据的句柄存储在一个小的备份文件中,该文件存储在块存储旁边。第二个是获取该备份文件并将原始数据写入 stdout。
在此过程中,zbackup 将识别之前见过的数据块并对其进行重复数据删除,然后在写入磁盘之前压缩任何新数据。在重复数据删除数据时,zbackup 使用一次移动一个字节的滑动窗口,这样,如果您在文件中插入单个字节,它仍然可以识别重复的块。这与 ZFS 中发现的块级重复数据删除形成对比。
要开始使用 zbackup,您必须从源代码安装它。这非常容易做到;只需按照 http://zbackup.org 网站上的说明进行操作即可。
假设您已安装 zbackup,并且 /usr/local/bin 在您的路径中,首先初始化一个块存储(在这些示例中,我以 root 身份运行,但这并非必要条件)
# zbackup init --non-encrypted /tmp/zbackup/
希望您不要将 /tmp 用于您的真实备份!您可以列出块存储,如下所示 - 该网站提供了有关内容去向的精彩信息。主要要记住的是备份;这是您的备份文件去的地方
# ls /tmp/zbackup
backups bundles index info
让我们备份一个数据库备份文件——第一次需要一段时间(清单 1)。
清单 1. 备份一个文件
# ls -l /tmp/database.sql
-rw-r--r-- 1 root root 406623470 Sep 14 17:41 /tmp/database.sql
# cat /tmp/database.sql | zbackup backup
↪/tmp/zbackup/backups/database.sql
Loading index...
Index loaded.
Using up to 8 thread(s) for compression
要检查它去了哪里,请查看清单 2。正如您所看到的,备份文件只有 135 个字节。大部分数据存储在 /bundles 中,并且小于原始数据库大小的十分之一。
清单 2. 检查备份
# ls -l /tmp/zbackup/backups/database.sql
-rw------- 1 root root 135 Sep 14 17:43
↪/tmp/zbackup/backups/database.sql
# du --max-depth=1 /tmp/zbackup/
8 /tmp/zbackup/backups
208 /tmp/zbackup/index
29440 /tmp/zbackup/bundles
现在,对备份文件进行少量更改以模拟一些使用,然后再次备份它(参见清单 3)。此示例说明了一个要点,即 zbackup 不会更改数据存储中的任何文件。您可以根据需要重命名 /backup 目录中的文件。您也可以在 /backups 下设置子目录,如清单 4 所示,其中备份最终工作。
清单 3. 再次备份文件
# cat /tmp/database.sql | zbackup --silent backup
↪/tmp/zbackup/backups/database.sql
Won't overwrite existing file /tmp/zbackup/backups/database.sql
清单 4. 备份文件,第 2 部分
# mkdir -p /tmp/zbackup/backups/1/2/3/
# cat /tmp/database.sql | zbackup --silent backup
↪/tmp/zbackup/backups/1/2/3/database.sql
这应该更快地完成,既因为文件被缓存,又因为大多数块已经被重复数据删除
# du --max-depth=0 /tmp/zbackup/
29768 /tmp/zbackup/
在此示例中,我对文件所做的更改仅略微增加了备份的大小。
现在让我们恢复第二个备份。只需将备份句柄传递给 zbackup restore,文件就会写入 stdout
# zbackup restore /tmp/zbackup/backups/1/2/3/database.sql >
↪/tmp/database.sql.restored
现在您可以检查您恢复的文件,以证明它与您最初备份的文件相同(清单 5)。
清单 5. 检查恢复的文件
# ls -l /tmp/database.sql*
-rw-r--r-- 1 root root 406622180 Sep 14 17:47 /tmp/database.sql
-rw-r--r-- 1 root root 406622180 Sep 14 17:53
↪/tmp/database.sql.restored
# md5sum /tmp/database.sql*
179a33abbc3e8cd2058703b96dff8eb4 /tmp/database.sql
179a33abbc3e8cd2058703b96dff8eb4 /tmp/database.sql.restored
当然,在大多数情况下,您不会备份单个文件。这就是 UNIX 哲学发挥作用的地方——因为 tar 可以从 stdin 读取并写入 stdout,所以您只需将 zbackup 链接到 tar 即可。清单 6 显示了一个示例,说明如何使用 tar 管道传输到 zbackup 来备份 /tmp/files/ 中的大型目录结构。
清单 6. tar 和备份目录
# tar -c /tmp/files | zbackup
↪--silent backup /tmp/zbackup/backups/files.tar
# du --max-depth=0 /tmp/zbackup
97128 /tmp/zbackup
现在在一个 zbackup 存储中存在数据库文件的两个备份和一个 /tmp/files 的 tar 备份。没有任何东西阻止您调用备份文件 files.tar.gz 或其他任何名称;但是,这稍后会非常令人困惑。如果您根据备份文件恢复到的文件的名称命名备份文件,则更容易弄清楚每个备份是什么。
现在您可以使用清单 7 中的示例恢复此备份。示例的大部分内容是创建要恢复到的目录并将恢复的备份与原始备份进行比较。
清单 7. 从 zbackup 恢复
# mkdir /tmp/files.restore
# cd /tmp/files.restore/
# zbackup --silent restore /tmp/zbackup/backups/files.tar | tar -x
# diff -rq /tmpfiles.restore/tmp/files/ /tmp/files/
如果您经常备份,则按日期在目录中组织备份是有意义的。清单 8 中的示例为每个月设置一个目录,然后为每一天设置一个子目录,最后为一天中的每个时间设置一个子目录——例如,2014-09/12/08:30/——并且该时间的所有备份都放在此目录中。
清单 8. 组织您的备份
# export DATEDIR=`date "+%Y-%m/%d/%H:%M"`
# mkdir -p /tmp/zbackup/backups/$DATEDIR
# tar -c /tmp/files | zbackup --silent backup
↪/tmp/zbackup/backups/$DATEDIR/files.tar
# cat /tmp/database.sql | zbackup backup
↪/tmp/zbackup/backups/$DATEDIR/database.sql
每天或每小时运行此命令,您可以恢复您制作的任何备份,追溯到时间的开始。对于我正在备份的文件,整个一年的 zbackup 数据小于存储单个未压缩的备份。
zbackup 目录具有极其好的属性,即其中的文件一旦写入就永远不会更改。这使得 rsync 非常快(因为只需要读取备份中的新文件),并且非常快地复制到 USB 磁盘等其他介质。这也使其成为使用 LVM 或 ZFS 进行文件系统快照等操作的理想选择。
在 zbackup 中备份后,您可以将其运送到中央服务器并将其放入 USB 或磁带,或者将其上传到 Amazon S3 甚至 Dropbox。
基准测试/结果这一切在理论上都不错,但关键问题是“它的性能如何?” 为了给您一个概念,我在一台服务器上运行了一些基准测试,该服务器具有同一应用程序的多个相似版本——例如,培训、开发、UAT。大约有 5GB 的数据库和 800MB 的网站文件。该服务器有八个内核和充足的内存,尽管在每次基准测试之前都刷新了所有缓冲区。
所有网站:这是一个包含 30,000 个文件的集合,大约占用 800MB 的空间。表 1 说明了结果。zbackup 提供的备份大约是 gzipped tar 文件大小的四分之一。每个新备份添加三个文件——根据设计,zbackup 永远不会修改文件,而只会添加文件。
表 1. 多个网站空间 | 时间 | 文件 | |
tar | 743M | 25 秒 | 1 |
tar & gzip | 382M | 44 秒 | 1 |
zbackup | 105M | 38 秒 | 203 |
zbackup 2 | 4K | 30 秒 | 206 |
zbackup 3 | 632k | 30 秒 | 209 |
第一次 zbackup 运行并备份整个目录时,需要更长的时间,因为池中没有重复数据删除的数据。在第一次运行时,所有八个内核都被充分利用。在较慢的机器上,由于 CPU 使用率高,吞吐量较低。
第二次,zbackup 在相同的文件夹结构上运行,仅使用了 4k 的额外存储空间。备份运行速度也更快,因为大部分数据已经存在。
第三次,在文件系统中放置了四个完全由 100,000 个随机字节组成的文件。
单个网站: zbackup 在第一个测试中的压缩性能在很大程度上是因为存在同一网站的多个相似副本。此测试仅备份其中一个网站以提供另一种类型的比较。
结果如表 2 所示。压缩结果并不比 gzip 好多少,这表明在执行多个网站时重复数据删除是多么有效。
表 2. 单个网站空间 | 时间 | 文件 | |
tar | 280M | 8 秒 | 1 |
tar & gzip | 74M | 9 秒 | 1 |
zbackup | 66M | 17 秒 | 131 |
数据库文件:这是数据库转储文件的备份,文本格式未压缩。结果如表 3 所示。
表 3. 数据库文件空间 | 时间 | 文件 | |
tar | 377M | 2 秒 | 1 |
tar & gzip | 43M | 10 秒 | 1 |
zbackup | 29M | 32 秒 | 192 |
zbackup 2 | 4M | 3 秒 | 200 |
zbackup 3 | 164K | 3 秒 | 210 |
第一次运行是 zbackup 备份 377M 的测试数据库。重复数据删除和压缩比 tar 和 gzip 提供了显着的增益,尽管它运行速度慢得多。
第二个 zbackup 是一个培训数据库,它与测试数据库类似,但它有额外的 10MB 数据,并且一些其他数据也不同。在这种情况下,zbackup 非常有效地删除了重复项,而几乎没有额外的存储成本。
最后的 zbackup 是从备份文件中随机删除行簇,以模拟来自更新和删除的更改。这是在短时间内备份数据库的典型情况,并且与我对真实世界性能的观察非常吻合。
网络性能:根据设计,zbackup 不会修改或删除文件。这意味着您需要在网络上同步的只是添加的文件数量和额外的磁盘空间。现有文件永远不需要更新。
我没有对此进行基准测试,而是查看了我们服务器的真实日志。同步 6GB 的数据和超过 30,000 个文件通常需要不到十秒钟。与之前 rsync 目录树和大型文件的方法(过去需要一到三分钟)相比,这是一个巨大的改进。
中央服务器的磁盘和网络速度较慢;但是,它可以轻松应对来自同步 zbackup 的负载。我怀疑即使是 Raspberry Pi 也具有足够的性能来充当同步目标。
正如他们所说,您的里程可能会有所不同。有许多因素会改变您获得的性能,例如
-
磁盘速度。
-
CPU 性能(对于第一次备份尤其重要)。
-
文件性质——例如,二进制数据库备份的压缩率低于文本备份。
-
同一数据的多个副本的存在。
由于重复数据删除数据,zbackup 特别容易受到文件损坏的影响。对单个文件的更改可能会使整个数据存储变得毫无用处。值得检查您的介质以确保它们处于良好状态。从好的方面来说,您可能可以在不到一小时的时间内将一年价值 200GB 数据的备份复制到另一个磁盘。
在同一 zbackup 存储中提供多个版本的备份与拥有多个副本不同。将您的 zbackup 存储复制到其他磁盘或服务器并不能解决问题。例如,如果有人要修改备份存储中的某些文件,然后将其盲目地复制到每台机器或磁盘,您将拥有许多无价值备份的精确副本。
因此,我包括文件系统的快照以防止这种情况发生,并且还轮换我们的介质并定期检查备份。作为替代方案,您可以仅从正在备份的服务器 rsync 新文件,而忽略删除或文件更新。
zbackup 的设计意味着检索备份也会检查其一致性,因此值得定期尝试恢复您的备份。
另一个需要考虑的点是,是否存在单个公司、凭据或密钥,如果泄露,可能会导致您的所有备份被销毁。虽然拥有多个介质和服务器很有用,但如果单个黑客可以销毁所有内容,那么您将像引言中提到的两家公司一样容易受到攻击。轮换异地物理介质是实现此目的的好方法,或者使用具有完全不同凭据集的单独服务器。
zbackup 使加密存储在备份中的数据相对简单。如果您将备份存储在不安全或第三方机器上,您可能需要使用此工具。在管理多台服务器的备份时,我更喜欢使用 LUKS 加密存储备份的介质。这包括服务器内的驱动器和可移动 USB 驱动器。
其他注意事项特别重要的是,您不要在将文件传递给 zbackup 之前将文件压缩或加密作为流程的一部分。否则,您会发现重复数据删除将完全无效。例如,Postgres 允许您在写入文件时压缩备份。如果使用此选项,您将无法从使用 zbackup 中获得任何好处。
在此处的架构中,我建议在每台服务器上而不是集中执行 zbackup。这意味着,尽管服务器内的重复项已合并,但服务器之间的重复项未合并。对于某些应用程序,这可能还不够好。在这种情况下,您可以考虑在虚拟化主机上运行 zbackup 以删除磁盘文件的重复数据。
zbackup 和 tar 都是面向流的协议。这意味着恢复单个文件需要计算机恢复整个备份并仅解压您需要的文件。对于小型备份,这可能没问题,但如果您的目录结构非常大,则可能值得单独备份目录而不是一次性备份。例如,您可以选择单独备份网站。
zbackup 目前受到数据读入并流式传输到重复数据删除过程的速度的限制。即使文件没有更改,也必须完整读取文件,然后再进行重复数据删除。这大致相当于 rsync -c
(即,校验和文件内容而不是仅比较文件元数据)。为了扩展到真正大的数据大小,zbackup 可能需要在自身中包含一些 tar 功能,这样,如果它可以确定文件没有更改(通过 inode 和元数据),它就可以在不读取文件的情况下删除该文件的重复数据。