可怕的备份故事
和很多人一样,我的职业生涯始于技术支持。就我而言,我是一家大型专业事务所的服务台团队的一员。除其他事项外,我们还负责为其他部门使用的多个系统执行 PC LAN 备份。对于一个特别重要的系统,我们购置了精新的磁带备份设备和大量的磁带。制定了程序,睡前备份成为标准。几个月后,一次崩溃导致系统瘫痪,所有数据丢失。此后不久,有人打电话来索要最新的备份磁带。磁带被找到并发送,并尝试恢复。然而,恢复失败了,因为磁带是 空白的。又有人打电话来索要倒数第二张备份磁带。这张磁带也被紧张地找到并发送,并尝试恢复。也失败了,因为这张磁带也是空白的。在一片沉默和解雇通知的目光中,当调用前三晚的磁带时,恐慌开始蔓延。这次尝试导致了大量的叫喊。
然后检查了所有磁带,它们全部都是空白的。更糟糕的是,问题不仅是磁带是空白的——它们甚至没有格式化!精新的备份设备不够智能,无法意识到磁带没有格式化,因此允许使用它们。注意:将好的数据写入未格式化的磁带绝不是一个好主意。
现在,不要误会我,备份程序本身是好的。问题是,没有人测试过整个过程——没有人尝试过恢复。那么,每次恢复都失败也就不足为奇了吗?
为了使备份工作,您需要做两件事:(1)定义并实施一个好的程序,以及(2)测试它是否有效。
直到今天,我仍然无法理解我的老板(对备份程序负有全面责任)是如何在这种事件中幸免于被解雇的。那里发生的事情一直让我记忆犹新。
当在 Linux 系统上进行备份时,许多标准工具可以帮助避免上述问题。Marcel Gagné 的优秀著作(请参阅“资源”)包含一个简单而有用的脚本,该脚本不仅执行备份,还验证备份是否顺利进行。然后,在每次备份后,脚本都会向 root 发送一封电子邮件,详细说明发生了什么。
我将在这里介绍 Marcel 脚本的修改版本的要点,以向您展示这个过程实际上有多么容易。这个 bash 脚本首先定义日志文件和错误文件的位置。然后,两个 mv 命令复制之前的日志文件和错误文件,以便检查倒数第二次备份(如果需要)
#! /bin/bash backup_log=/usr/local/.Backups/backup.log backup_err=/usr/local/.Backups/backup.err mv $backup_log $backup_log.old mv $backup_err $backup_err.old
在日志文件和错误文件准备就绪后,几个 echo 命令将消息(注意使用 >>)附加到每个文件中。消息包括当前日期和时间(使用反引号 date 命令访问)。然后,cd 命令更改为要备份的目录的位置。在本例中,该目录是 /mnt/data,但它可以是任何位置
echo "Starting backup of /mnt/data: `date`." >> $backup_log echo "Errors reported for backup/verify: `date`." >> $backup_err cd /mnt/data
然后开始备份,使用久经考验的 tar 命令。-cvf 选项请求创建新归档 (c)、详细模式 (v) 以及要备份到的文件/设备的名称 (f)。在本例中,我们备份到 /dev/st0,即连接的 SCSI 磁带驱动器的位置
tar -cvf /dev/st0 . 2>>$backup_err
此命令产生的任何错误都会发送到 STDERR(标准错误)。上面的命令利用此行为,将发送到 STDERR 的任何内容也附加到错误文件中(使用 2>> 指令)。
备份完成后,脚本然后使用 mt 命令倒带磁带,然后使用另一个 tar 命令(-t 选项列出命名归档中的文件)列出磁带上的文件。这是一种验证磁带内容的简单方法。和以前一样,我们将此 tar 命令期间报告的任何错误附加到错误文件中。此外,信息性消息会在适当的时候添加到日志文件中
mt -f /dev/st0 rewind echo "Verifying this backup: `date`" >>$backup_log tar -tvf /dev/st0 2>>$backup_err echo "Backup complete: `date`" >>$backup_log
为了结束脚本,我们将错误文件连接到日志文件(使用 cat),然后通过电子邮件将日志文件发送给 root(其中 mail 命令的 -s 选项允许指定适当的主题行)
cat $backup_err >> $backup_log mail -s "Backup status report for /mnt/data" root < $backup_log
这就是 Marcel 表面上简单的解决方案,用于执行经过验证的备份并将结果通过电子邮件发送给感兴趣的方。如果我们多年前就拥有类似的东西就好了。
几年后,我发现自己在一家新公司担任 IT 经理。我被要求做的第一件事之一是为新获得的工资单系统定义和实施备份程序。我照做了。
在我看来,该程序是好的。有大量的格式化空白磁带,这些磁带每天轮换三个星期。备份磁带存放在工资单所在建筑物以外的建筑物中的锁着的柜子里。磁带必须登记进出。执行备份的责任“委托”给了工资单部门。IT 部门提供设备,设置一切,测试备份是否实际发生(以及磁带是否可以成功用于恢复),并培训工资单部门员工。现在,不要误会我,我并不是不相信上帝。只是我确信上帝有一个邪恶的双胞胎,他喜欢嘲笑我们。在这种情况下,邪恶的双胞胎上帝从天上发出了一道巨大的闪电,并将其瞄准了工资单所在的建筑物。在直接击中后,闪电击穿了保护工资单硬件的浪涌抑制器,并最终烧毁了硬盘。惊慌失措的电话打给了我,IT 经理。
在向工资单经理保证一切正常并注意到过去三个星期每天都有备份的情况下,我派遣了一名技术人员去调查。果然,硬盘坏了。紧急订购了替换件,第二天早上就到了。我们立即开始工作,让一切重新运转起来。
最新的完整备份磁带用于恢复系统。这很顺利:操作系统已恢复,所有应用程序和用户设置都已到位。然后,最新的备份磁带用于将系统恢复到闪电击中之前的最后已知良好状态。快速执行工资单应用程序看起来没问题。我们都回到了办公桌,很高兴我们躲过了这个特别糟糕的子弹。
然后电话来了:“我们丢失了过去两周的工资单数据。”这怎么可能?我们检查了是否使用了正确的磁带进行恢复。是的。我们检查了日志,看看磁带是否已发放并签收。是的;备份每天晚上都按计划进行。我们检查了用于将系统恢复到其最后已知良好状态的实际备份磁带,果然,上面没有工资单数据。实际上,上面几乎没有任何东西。再次检查日志,我们注意到,在之前的两周里,一位非指定的备份人员一直在签出磁带。我们检查了磁带,发现备份的唯一文件属于这位其他工作人员。发生的事情是,指定的备份人员休假了,并将夜间备份委托给了一位同事。不幸的是(对我们来说),这位同事没有备份整个硬盘所需的权限;只有指定的备份人员才拥有正确的权限。相信邪恶的双胞胎上帝会在我们指定的备份人员休假时测试我们的备份程序!这个可怕的备份故事的寓意是 永远不要低估人为因素。
因此,为了使备份工作,您实际上需要做三件事:(1)定义并实施一个好的程序,(2)测试它是否有效,以及(3)经常审查您的程序。
为备份创建特定的用户 ID 将有助于避免上述问题,而不是依赖于特定的用户(具有正确的权限)来执行工作。更好的情况是,对任何一个用户的依赖性都最小化。如果用户每天只需更换磁带,事情就会更加万无一失。同样,Linux 和一个标准工具可以提供帮助,该工具的名称是 cron。假设上面的脚本名为 mntdata.backup,并且它位于 /usr/local/.Backups/mntdata.backup 中,请运行
0 21 * * 1-5 /usr/local/.Backups/mntdata.backup
现在,只需要一个手动程序,在每个工作日开始时更换磁带。然后标记磁带并安全存储。对此 cron 条目的一个小改进是将脚本中的任何错误捕获到日志文件中(以防其执行出现问题)。
Marcel Gagné,《Linux 系统管理:用户指南》第 17 章,Addison-Wesley (Pearson Education),2002 年。ISBN:0-201-71934-7。
Paul Barry 不再担心备份磁带。在过去的五年里,他一直在爱尔兰卡洛理工学院任教。他是 使用 Perl 进行网络编程(Wiley 2002 年出版)的作者。