使用 rdiff-backup 和 rdiffWeb 进行备份和恢复

作者:Adrian Klaver

rdiff-backup 是一个基于 Python 的备份程序,它使用 rsync 算法。它类似于 rsync,因为它将源目录同步到镜像目录。不同之处在于它使用反向差异来维护从当前版本追溯的文件版本。该程序可在 rdiff-backup.nongnu.org 获取。在撰写本文时,当前的稳定版本是 1.2.8。提供源代码和二进制版本。该程序适用于 POSIX 系统和 Windows,并且可以跨平台同步。除了在本文中描述 rdiff-backup 之外,我还将演示 rdiffWeb,这是一个基于 Web 的界面,用于从 rdiff-backup 目录恢复文件。

rdiff-backup 使用 librsync (librsync.sourceforge.net) 作为其 rsync 提供程序。有关更多详细信息,请参阅 librsync.sourcefrog.net/doc/librsync.html,特别是 librsync.sourcefrog.net/doc/rdiff.html,其中解释了 rsync 和差异过程的工作原理。为了解释上述站点的信息,librsync 允许比较两个文件并生成差异,而无需同时访问文件的两个副本。相反,旧文件的签名与新文件进行比较。签名包含对旧文件中的块计算的校验和。签名校验和用于查找新文件中匹配的块,然后计算差异。

优点是,当跨网络比较文件时,只需通过线路发送签名即可生成差异。缺点是校验和是面向块的,因此影响多个块的小更改将导致比其他差异方法更大的差异。上述方法在字节级别工作,并且没有文件名、权限等更高级别的概念。这就是 rdiff-backup 的用武之地。它提供了将字节流与必要的元数据包装在一起的机制。

rdiff-backup 的基本操作如下。备份从源目录完成到目标目录。目标目录包含文件最新版本的镜像。此外,rdiff-backup 在目标目录中创建一个名为 rdiff-backup-data 的子目录。rdiff-backup 将执行备份版本控制所需的信息保存在此子目录中。顶层是包含备份中文件的元数据以及有关备份状态信息的文件。

对于那些感兴趣的人,mirror-metadata* 文件包含特定的文件信息,例如用户、组、权限等。还包括名为 increments 的子目录。此处保存着来自文件当前版本的反向差异。差异本身经过 gzip 压缩以节省空间。

increments 子目录中的目录结构与镜像目录的目录结构匹配。因此,如果镜像具有 Documents/Personal/,则 increments 也将具有 Documents/Personal/。除了差异之外,目录还包含作为占位符或元数据的文件。例如,将存在零长度的时间戳 *.dir 文件,指示何时完成备份。还有 *.missing 文件,这些文件是追溯创建的,用于标记文件出现之前的备份。例如,如果在星期一完成备份,并且目录 A 具有 file_1,然后在星期二完成备份,并且目录 A 具有文件 file_1 和 file_2,则将创建 file_2_<timestamp>.missing 文件。时间戳将是星期一备份的时间。为了了解事物是如何工作的,我建议监视 rdiff-backup-data 目录和子目录一段时间。一旦你这样做,它将变得更加明显该过程是如何工作的。

现在让我们进入有趣的部分,创建备份。要从本地目录备份到本地目录,请使用命令

rdiff-backup software_projects /var/backups/test_backup

在这种情况下,test_backup 将具有一个子目录 software_projects,其中包含上述 rdiff-backup-data 子目录(图 1)。

Using rdiff-backup and rdiffWeb to Back Up and Restore

图 1. 完整备份的目录列表

为了具有一定的故障冗余,更实用的情况是将备份到另一台机器。在这种情况下,rdiff-backup 使用 SSH 建立机器之间的连接。这意味着您需要为相关机器设置 SSH。首选方法是设置公钥身份验证,以便不需要密码。还需要在远程计算机上安装 rdiff-backup。在这种情况下,命令是

rdiff-backup software_projects \
                 user@host.example.com::/var/backups/test_backup

请注意,可以使用以下命令自定义 rdiff-backup 如何建立其远程连接--remote-schema开关。默认连接字符串是'ssh -C %s rdiff-backup --server',其中 %s 是主机信息。这使用 SSH 的默认端口 (22)。如果您的 SSH 设置为侦听不同的端口,请执行以下操作

--remote-schema 'ssh -p xxxxx -C \%s  rdiff-backup --server'

此处显示的两种情况都很简单,并且只会将 /software_projects 及其所有子目录完全备份到 /var/backups 中的相应目录。可以以多种方式微调 rdiff-backup 的行为。我在此处展示的只是可能情况的一个示例。在 rdiff-backup.nongnu.org/rdiff-backup.1.html 上花一些时间来获得完整的了解。这只是手册页的 HTML 转换,因此您可以通过 man 在您的机器上找到相同的信息,假设您已安装 rdiff-backup。特别是,查看文件选择部分。实际上,多次浏览该部分。那里有很多功能,但前几次浏览时有点令人困惑。

让我们首先排除一些我们实际上不想备份的文件

rdiff-backup --exclude '**track_stocks' \
                software_projects \
                    /var/backups/test_backup

在此示例中,我们排除了整个 track_stocks 目录(参见图 2 并将其与图 1 进行比较)。'**track_stocks'匹配(因此,排除)任何以 track_stocks 结尾的路径名(有关更多详细信息,请参见下文)。

Using rdiff-backup and rdiffWeb to Back Up and Restore

图 2. 显示排除 track_stocks 目录效果的目录列表

现在,让我们反过来,专门包含某些内容,排除所有其他内容

rdiff-backup --include '**linux_journal_articles' \
             --exclude '**' \
                software_projects \
                    /var/backups/test_backup

这里要记住的重要事项是您的--include--exclude选项的顺序很重要。在上面的示例中,包含 /linux_journals_articles 优先于排除所有内容('**')。图 3 显示了结果。我可以继续介绍所有可能的组合,但以上内容涵盖了基础知识。首先使用一些测试文件来掌握 --include 和 --exclude 之间的交互。另请注意,每个包含或排除模式都需要在一个单独的开关中。

Using rdiff-backup and rdiffWeb to Back Up and Restore

图 3. 仅包含 linux_journal_articles 目录的备份目录列表。

让我进一步解释包含和排除模式匹配的工作原理。如前所述,顺序决定优先级,因此较早指定的模式会覆盖较晚指定的模式。包含/排除开关与扩展的 shell globbing 模式一起使用。在“标准” shell globbing 中,* 匹配除 / 之外的任何字符。扩展 globbing 添加了 ** 模式,该模式匹配任何字符,包括 /。此外,模式可以以ignorecase作为前缀,以匹配,而与大写/小写无关。有关更多详细信息,请参见上面的链接。至于模式匹配的工作原理,我找不到比文档中更好的描述了

--exclude 模式选项在以下情况下匹配文件:1) 模式可以扩展为文件的文件名,或者 2) 文件位于选项匹配的目录内。

相反,--include 模式在以下情况下匹配文件:1) 模式可以扩展为文件的文件名,2) 文件位于选项匹配的目录内,或者 3) 文件是一个目录,其中包含选项匹配的文件。

这实际上导致的结果是,如果您包含一个文件,则构成其路径的目录也将被包含在内,而排除一个文件只会排除它,而不会排除其上方的目录。

对于简单的情况,先前显示的命令行包含和排除效果很好。但是,随着包含和排除参数数量的增加,它们变得笨拙。幸运的是,还有另一种指定参数的方法,即文件列表。有三种变体:filelist、filelist-stdin 和 globbing-filelist。这三种形式都采用包含或排除前缀,例如,--include-filelist。但这有点误导,因为可以在文件中使用 + 和 - 分别指定包含和排除参数,这会覆盖前缀。为了保持一致性,我将使用 globbing-filelist,因为它遵循与命令行上的 --include 和 --exclude 选项相同的规则。其他形式不遵循 globbing 扩展和包含模式匹配行为。因此,要使用文件列表复制上面的最后一个命令,请执行

rdiff-backup --include-globbing-filelist rdiff_globbing.txt \
                software_projects \
                    /var/backups/test_backup

rdiff_globbing.txt 的内容是

+ **linux_journal_articles
- **

结果与图 3 中所示相同。

创建备份是好事,但是如果您无法从中恢复文件,那么它们几乎毫无用处。恢复,最简单地说,只是备份的反向操作。换句话说,命令行上目录的顺序是相反的——镜像在前,要恢复到的目录在后。有一个重要的警告:默认情况下,rdiff-backup 不会覆盖现有文件/路径进行恢复。可以将其视为一种脚/枪安全装置。您有两种选择,恢复到另一个路径或使用 --force 开关来覆盖默认行为。

rdiff-backup 为您提供了两种基本方法来恢复文件的特定版本:基于时间和基于编号。

基于时间的恢复基于增量的时间。假设您有一个 cron 作业,该作业每天晚上在同一时间执行备份,那么您将拥有追溯时间并带有时间戳的增量。要查看您有哪些增量,请执行

rdiff-backup --list-increments \
                user@host.example.com::/var/backups/lj_article

您也可以使用-l而不是--list-increments。此处的target是备份目录。以下是我针对 EC2 实例运行 cron 作业以使用本文的更改进行播种的实际输出(使用不同的目标)

increments.2010-01-16T02:15:05Z.dir   Fri Jan 15 18:15:05 2010
increments.2010-01-17T02:15:06Z.dir   Sat Jan 16 18:15:06 2010
increments.2010-01-18T02:15:05Z.dir   Sun Jan 17 18:15:05 2010
increments.2010-01-19T02:15:06Z.dir   Mon Jan 18 18:15:06 2010
increments.2010-01-20T02:15:06Z.dir   Tue Jan 19 18:15:06 2010
increments.2010-01-21T02:15:05Z.dir   Wed Jan 20 18:15:05 2010
increments.2010-01-22T02:15:05Z.dir   Thu Jan 21 18:15:05 2010
increments.2010-01-23T02:15:05Z.dir   Fri Jan 22 18:15:05 2010
increments.2010-01-24T02:15:06Z.dir   Sat Jan 23 18:15:06 2010
increments.2010-01-25T02:15:06Z.dir   Sun Jan 24 18:15:06 2010

掌握此信息后,我可以执行以下操作以从特定时间恢复增量

file=/var/backups/lj_article/software_projects
file="$file/linux_journal_articles/rdiff_backup/lj_rdiff_article.txt"

rdiff-backup --restore-as-of 2010-01-20T02:15:06Z \
                 user@ec2.example.com::$file \
                     test/lj_rdiff_article.txt

您也可以使用-r而不是--restore-as-of.

然后,我将拥有本文在该特定时间备份时的版本。有一种更用户友好的变体,它使用不同的时间视图。在该方法中,您将时间指定为间隔,使用以下语法整数[修饰符],其中修饰符为 s、m、h、D、W、M 和 Y,它们代表的时间段分别为秒、分钟、小时、天、周、月和年。一个例子是-r 2D12h,它翻译为“恢复 2 天 12 小时前的文件”。那么问题是,如果没有增量正好落在那个时间怎么办?答案是,rdiff-backup 使用最接近该时间且不晚于指定时间的增量。因此,对于此示例,如果存在 2 天 18 小时前的增量和一个 2 天 11 小时前的增量,它将使用 2 天 18 小时前的增量。

第二种指定恢复的方法,基于编号的恢复,基于会话编号的概念,其中语法为整数[B],其中 0B 是当前的镜像版本。因此,要从第二个最新的备份恢复,您将执行-r 2B.

尽管恢复选项功能强大,但它们确实需要命令行知识以及对 rdiff-backup 的一定程度的熟悉。为了简化最终用户的体验,让我们看一下 rdiffWeb,这是一个基于 Web 的界面,用于恢复使用 rdiff-backup 备份的文件。

但首先,这里有一些快速的通用使用技巧。每个备份会话都在事务中完成。这意味着如果会话中断,则下次执行备份时,将删除先前未完成的备份。如果要检查此情况,请执行

rdiff-backup --check-destination-dir  /var/backups/test_backup

如果目录中存在不完整的备份,它将被回滚。会话的事务性质意味着如果您通过不稳定的连接远程备份,则可能会出现问题。这在执行大型数据集的初始备份时尤其重要。避免此潜在问题的一种解决方案是执行本地 rdiff-backup 备份,然后使用 rsync 将本地 rdiff 镜像同步到远程站点。rsync 允许中断会话,并且可以重新运行以完成传输。远程镜像完成后,将 rdiff-backup 镜像目录从本地更改为远程。从那时起,您将仅传输更改。

其次,每次执行备份时,它都会创建一个增量,随着时间的推移,这些增量会累积起来。要查看备份目录正在使用的空间,请执行以下操作

rdiff-backup --list-increment-sizes \
                user@ec2.example.com::/var/backups/lj_article


        Time                   Size    Cumulative size
----------------------------------------------------------------------
Tue Jan 26 18:15:05 2010     5.98 MB       5.98 MB   (current mirror)
Mon Jan 25 18:15:07 2010     1.14 KB       5.98 MB
Sun Jan 24 18:15:06 2010     1.54 KB       5.99 MB
Sat Jan 23 18:15:06 2010     0 bytes       5.99 MB
Fri Jan 22 18:15:05 2010     0 bytes       5.99 MB
Thu Jan 21 18:15:05 2010     0 bytes       5.99 MB
Wed Jan 20 18:15:05 2010     0 bytes       5.99 MB
Tue Jan 19 18:15:06 2010     25.8 KB       6.01 MB
Mon Jan 18 18:15:06 2010     1.22 KB       6.01 MB
Sun Jan 17 18:15:05 2010     32.7 KB       6.04 MB
Sat Jan 16 18:15:06 2010     0 bytes       6.04 MB
Fri Jan 15 18:15:05 2010     0 bytes       6.04 MB
Thu Jan 14 18:15:05 2010     0 bytes       6.04 MB
Wed Jan 13 18:15:05 2010     0 bytes       6.04 MB
Tue Jan 12 18:15:05 2010     0 bytes       6.04 MB
Mon Jan 11 18:15:06 2010     0 bytes       6.04 MB
Sun Jan 10 18:15:06 2010     0 bytes       6.04 MB
Sat Jan  9 18:15:07 2010     0 bytes       6.04 MB
Fri Jan  8 18:15:08 2010     0 bytes       6.04 MB
Thu Jan  7 18:15:06 2010     0 bytes       6.04 MB
Wed Jan  6 18:15:06 2010     31.5 KB       6.07 MB
Wed Jan  6 07:05:52 2010   194 bytes       6.07 MB

这是查看存储空间正在何处使用以及备份目录总量的不错方法。除非您拥有无限的备份磁盘空间,否则在某个时候,您将需要开始修剪备份目录。要修剪增量,请使用--remove-older-than 'time',其中时间的指定方式与恢复时使用的指定方式相同。对于我自己的个人数据,我有一个 cron 作业,每天晚上运行

rdiff-backup --remove-older-than 7D 'destination_dir'

这保留了我备份的滚动七天版本历史记录。

现在如承诺:rdiffWeb,可在 www.rdiffweb.org 获取。rdiffWeb,像 rdiff-backup 一样,是用 Python 编写的。它使用 CherryPy 来提供其页面。我正在使用 0.6.3 版本,这是撰写本文时的测试版本。主要原因是 0.6.3 使用 SQLite 作为其数据存储,而不是稳定版本 0.5.1 所使用的 MySQL。SQLite 与 Python 2.5+ 捆绑在一起,因此减少了一件需要设置的事情。请务必按照上面列出的页面上的“安装”链接进行操作。安装非常简单,但是您需要进行一些手动更改才能使程序正常运行。请注意,可以为 https 设置 rdiffWeb,这正是本文使用它的方式。

首次访问 rdiffWeb 时,系统将提示您设置管理员帐户。完成后,您就可以设置用户并使用“用户偏好设置”(图 4)。值得注意的是“目录恢复格式”选项。如果您要恢复整个目录,这将发挥作用。rdiffWeb 将根据设置创建 zip 文件或 gzipped tarball,这对于处理 Windows 或 UNIX 用户很有用。同样值得注意的是“更新备份位置”按钮。这是一种强制 rdiffWeb 查找您已添加的任何新备份目录的方法。它会自行找到它们,但通常不会立即找到。

Using rdiff-backup and rdiffWeb to Back Up and Restore

图 4. rdiffWeb 设置中的“用户偏好设置”页面

重点是查找文件。当您登录时,将显示一个页面,其中包含您拥有权限的备份目录。然后,您可以遍历目录树以获取您想要的文件或目录。图 5 显示了本文的四个可用版本。单击时间戳将打开浏览器下载对话框,允许您将文件下载到您选择的位置。如果要下载目录,请单击“恢复文件夹”链接。然后,您将被带到一个页面,其中列出了各种可用的时间戳版本。选择合适的版本,目录及其内容将根据您的“用户偏好设置”页面上指定的“目录恢复格式”进行捆绑。

Using rdiff-backup and rdiffWeb to Back Up and Restore

图 5. 在 rdiffWeb 中选择文件版本

当您希望对备份进行版本控制,而无需保留版本的完整副本时,rdiff-backup 是一个有用的工具。它相对容易设置。程序的命令行性质既是优点又是缺点。优点是它适用于脚本编写。缺点是并非所有用户都精通命令行,因此有了关于 rdiffWeb 的部分。我的运行方法是让 cron 作业执行备份,然后使用 rdiffWeb 进行恢复。

最后,这里有一些关于备份增量性质的总体观察。节省的空间量取决于使用情况。rdiff-backup 保存所有信息,因此,如果您执行大量删除操作,则备份目录将充满已删除的文件,除非您定期修剪。如前所述,文件比较的块性质对于跨多个块的小更改效率不高。我提出这一点是为了提示您在一段时间内监控目标目录的磁盘空间,直到您对您的使用模式如何影响它有所了解。但总的来说,我发现 rdiff-backup 在备份大小和备份多功能性之间提供了很好的折衷方案。

Adrian Klaver 希望认为计算机并没有真正统治他的生活,并且为此,他偶尔会发现自己凝视着拍打在海滩上的海浪。就极客资历而言,他是华盛顿州贝灵厄姆 LinuxFest Northwest 的组织者之一。

加载 Disqus 评论