避免服务器灾难

担心您的服务器会宕机吗?您应该担心。这里有一些为服务器所有者准备的灾难规划技巧。

如果您拥有一辆汽车或一栋房子,您几乎肯定会购买保险。保险看起来像是在浪费一大笔钱。您每年都支付保费,并确保您以最优惠的价格获得尽可能好的保障,然后您希望永远不需要使用保险。保险看起来真的很划不来——直到您遇到灾难并意识到,如果不是因为保险,您可能已经破产了。

不幸的是,灾难和事故是计算机行业生活中不可避免的事实。因此,正如您购买保险并希望永远不必使用它一样,您也需要花时间来确保系统的安全性和可靠性——不是因为您希望灾难发生,甚至不期望它们发生,而是因为您必须这样做。

如果您的网站只是您公司的在线宣传册,然后宕机几个小时甚至几天,那只会令人尴尬和恼火,但在经济上不会造成痛苦。但是,如果您的网站就是您的业务,当您的网站宕机时,您就会亏钱。如果是这种情况,那么至关重要的是,要确保您的服务器和软件不仅不太可能宕机,而且在发生宕机时也易于恢复。

我为什么要写这个主题?好吧,不妨说这个问题在我开始写这篇文章之前就发生在我自己身上。多年来,我一直在帮助世界各地的客户确保其系统的可靠性,但我犯了一个错误,没有对自己系统做到同样彻底。(正如谚语所说,“鞋匠的孩子赤脚走”。)这意味着,就在我为Python开发者推出新的在线产品后不久,一次看似微不足道的升级变成了一场灾难。事实证明,我采取的预防措施还不够充分——而且在我写这篇文章时,我仍在重新搭建我的Web服务器。我会挺过去的,我的服务器和业务也会挺过去的,但这真是一次痛苦而重要的教训——为了避免将来再次发生,我几乎愿意做任何事。

因此,在本文中,我将介绍一些我多年来使用的技术,以保持服务器的安全和稳定,并减少彻底崩溃的可能性。您可以将这些技术视为您服务器的保险,这样即使出现问题,您也能够相当快地恢复。

我应该指出,这里的大部分建议都假设您的架构中没有冗余——也就是说,只有一个Web服务器和(最多)一个数据库服务器。如果您有能力拥有每种类型的多台服务器,那么这类问题往往会少得多。但是,这并不意味着它们会完全消失。此外,尽管人们喜欢谈论需要大量硬件才能运行的重型Web应用程序,但事实是,许多企业都在小型的、一到两台计算机的服务器上运行。而且,这些企业不需要更多;从额外服务器获得的投资回报率(ROI)是无法证明其合理性的。然而,良好的备份和恢复计划的投资回报率是巨大的,因此值得投资。

Web应用程序的组成部分

在讨论灾难准备和恢复之前,重要的是要考虑Web应用程序的不同组成部分,以及这些不同的部分对您的规划意味着什么。

多年来,我的网站非常小而简单。即使它包含一些简单的程序,这些程序通常也用于发送电子邮件或动态地向访问者显示不同的资源。整个站点由一些静态HTML、图像、JavaScript和CSS组成。不需要数据库或其他复杂的东西。

另一方面,许多人拥有成熟的Web应用程序,它们运行在多台服务器上,带有一个或多个数据库和缓存,以及带有经过广泛编辑的配置文件的HTTP服务器。

但是,即使考虑到这两个极端情况,您也可以看到Web应用程序仅由几个部分组成

  • 应用程序软件本身。

  • 该应用程序的静态资源。

  • HTTP服务器的配置文件。

  • 数据库配置文件。

  • 数据库模式和内容。

假设您正在使用高级语言,例如Python、Ruby或JavaScript,那么此列表中的所有内容要么是文件,要么可以转换为文件。(所有数据库都允许将其内容“转储”到磁盘上,转换为一种可以加载回数据库服务器的格式。)

考虑一个仅包含应用程序软件、静态资源和配置文件的站点。(换句话说,不涉及数据库。)在许多情况下,这样的站点可以可靠地备份在Git中。实际上,我更喜欢将我的站点保存在Git中,备份在商业托管服务(例如GitHub或Bitbucket)上,然后使用Capistrano之类的系统进行部署。

换句话说,您在自己的开发机器上开发站点。每当您对所做的更改感到满意时,您就将更改提交到Git(在您的本地机器上),然后执行git push到您的中央存储库。为了部署您的应用程序,您然后使用Capistrano执行cap deploy,它从中央存储库读取数据,将其放入服务器文件系统上的适当位置,然后您就可以开始了。

这个系统在几个不同的方面保护您的安全。代码本身至少位于三个位置:您的开发机器、服务器和存储库。这些中央存储库往往相当可靠,仅仅是因为确保事物的可靠性符合托管公司的经济利益。

我应该补充一点,在这样的情况下,您还应该将HTTP服务器的配置文件包含在您的Git存储库中。这些文件不太可能经常更改,但我可以根据经验告诉您,如果您正在从危机中恢复,您最不想考虑的事情就是您的Apache配置文件应该是什么样子。将这些文件复制到您的Git存储库中就可以很好地工作。

备份数据库

您可能会争辩说,“网站”和“Web应用程序”之间的区别在于数据库。长期以来,数据库一直是许多Web应用程序的后端动力,这是有充分理由的——它们允许您可靠且灵活地存储和检索数据。现代开源数据库提供的强大功能在十年前或二十年前是不可想象的,并且没有理由认为它们在未来会变得不可靠。

然而,仅仅因为您的数据库相当可靠,并不意味着它不会出现问题。这意味着您需要保留数据库内容的快照(“转储”),以防数据库服务器损坏信息,并且您需要回滚到以前的版本。

我最喜欢的解决此类问题的方法是定期转储数据库,最好是每小时一次。这是一个我使用过的一种shell脚本,用于创建此类定期数据库转储


#!/bin/sh

BACKUP_ROOT="/home/database-backups/"
YEAR=`/bin/date +'%Y'`
MONTH=`/bin/date +'%m'`
DAY=`/bin/date +'%d'`

DIRECTORY="$BACKUP_ROOT/$YEAR/$MONTH/$DAY"
USERNAME=dbuser
DATABASE=dbname
HOST=localhost
PORT=3306

/bin/mkdir -p $DIRECTORY

/usr/bin/mysqldump -h $HOST --databases $DATABASE -u $USERNAME
 ↪| /bin/gzip --best --verbose >
 ↪$DIRECTORY/$DATABASE-dump.gz

上面的shell脚本首先定义了一堆变量,从我想存储备份的目录,到日期的各个部分(存储在$YEAR、$MONTH和$DAY中)。这样做是为了我可以为每月的每一天设置一个单独的目录。当然,我可以进一步为每个小时设置单独的目录,但我发现我很少需要一天中的多个备份。

一旦我定义了这些变量,我就使用mkdir命令创建一个新目录。-p选项告诉mkdir,如有必要,它应该创建它需要的所有目录,以便整个路径都存在。

最后,我运行数据库的“转储”命令。在这种特定情况下,我使用的是MySQL,所以我使用的是mysqldump命令。此命令的输出是一个SQL流,可用于重新创建数据库。因此,我从mysqldump获取输出并将其管道传输到gzip,后者压缩输出文件。最后,生成的转储文件以压缩形式放置在每日备份目录中。

根据数据库的大小和您手头的磁盘空间量,您必须决定您希望多久运行一次转储,以及多久清理一次旧转储。我从经验中知道,每小时转储一次可能会导致一些负载问题。在我使用过的一台虚拟机上,整体管理团队对我每小时转储和压缩感到不满,他们认为这是不必要地使用系统资源。

如果您担心您的系统会耗尽磁盘空间,您可能很想运行一个空间检查程序,该程序会在文件系统的可用空间不足时提醒您。此外,您可以运行一个cron作业,使用find擦除某个截止日期之前的所有转储文件。我总是对自动擦除备份的程序有点紧张,所以我通常不喜欢这样做。相反,我运行一个程序,如果磁盘使用率超过85%(通常足够低,可以确保即使我在长途飞行中也能及时解决问题),它会警告我。然后我可以进去手动删除有问题的文件。

当您备份数据库时,您应该确保同时备份该数据库的配置。数据库模式和数据(它们是转储文件的一部分)当然很重要。但是,如果您发现自己必须从头开始重新创建服务器,您会想确切地知道您是如何配置数据库服务器的,特别是文件系统配置和内存分配。我倾向于将PostgreSQL用于我的大部分工作,虽然postgresql.conf很容易理解和配置,但我仍然喜欢将其与我的转储文件一起保留。

另一件至关重要的事情是偶尔检查您的数据库转储,以确保它们以您希望的方式工作。事实证明,我以为我正在做的备份实际上并没有发生,这在很大程度上是因为我修改了shell脚本,并且没有仔细检查它是否正在创建有用的备份。偶尔取出一个转储文件并将其恢复到单独的(和离线的!)数据库以检查其完整性是一个好习惯,既可以确保转储正在工作,又可以确保您记住在紧急情况下如何恢复它。

存储备份

但是等等。拥有这些备份可能很棒,但是如果服务器完全宕机了怎么办?在代码的情况下,我提到要确保它位于多台机器上,以确保其完整性。相比之下,您的数据库转储现在位于服务器上,这样如果服务器发生故障,您的数据库转储将无法访问。

这意味着您需要将数据库转储存储在其他地方,最好是自动存储。您如何做到这一点?

对于这个问题,有一些相对容易且廉价的解决方案。如果您有两台服务器——理想情况下在不同的物理位置——您可以使用rsync将文件从一台复制到另一台。不要rsync数据库的实际文件,因为这些文件可能会在传输过程中损坏,并且不适合在服务器运行时复制。相比之下,您创建的转储文件完全可以移动到其他地方。设置一个远程服务器,并为处理这些备份传输的用户专门设置一个用户,应该不会太难,并且会在确保数据安全方面大有帮助。

我应该指出,以这种方式使用rsync基本上需要您设置无密码SSH,以便您可以进行传输,而无需亲自到场输入密码。

另一种可能的解决方案是亚马逊的简单存储服务(S3),它以非常低的价格提供惊人的磁盘空间量。我知道许多公司使用S3作为简单的(尽管速度较慢)备份系统。您可以设置一个cron作业来运行一个程序,该程序将特定数据库转储文件目录的内容复制到特定服务器上。这里的假设是,您永远不会使用这些备份,这意味着一旦您在服务器上工作,S3的慢速搜索和访问将不会成为问题。

类似地,您可能会考虑使用Dropbox。Dropbox以其桌面客户端而闻名,但它有一个“无头”的、基于文本的客户端,可以在没有GUI连接的Linux服务器上使用。Dropbox的一个不错的优势是您可以与任意数量的人共享文件夹,这意味着您可以让Dropbox自动将您的备份数据库分发到各处,包括您的团队中的许多人。备份会到达他们的Dropbox文件夹中,您可以确保LAMP是有条件的。

最后,如果您正在运行WordPress站点,您可能需要考虑VaultPress,这是一个付费备份系统。我必须承认,在我因数据库备份错误而导致服务器宕机之前的几周里,我一直在WordPress中看到VaultPress的广告。“谁会购买那个?”,我问自己,心想我足够聪明,可以自己做备份。当然,在灾难发生并且我的数据库被毁后,我意识到每年花30美元备份所有数据是很便宜的,我应该早点这样做。

结论

当涉及到您的服务器时,与其像一个乐观的程序员那样思考,不如更像一个保险代理人那样思考。也许灾难不会发生,但如果真的发生了,您能够恢复吗?确保即使您的服务器完全不可用,您也能够启动您的程序和任何关联的数据库至关重要。

我首选的解决方案包括结合使用Git存储库来存储代码和配置文件,分布在多台机器和服务上。但是,对于数据库,仅仅转储数据库是不够的;您需要将转储文件放到单独的机器上,最好定期测试备份文件。这样,即使出现问题,您也能够在短时间内恢复。

Reuven Lerner 在世界各地的公司教授 Python、数据科学和 Git。您可以订阅他免费的每周“更好的开发者”电子邮件列表,并从他的书籍和课程中学习,网址为 http://lerner.co.il。Reuven 与他的妻子和孩子住在以色列的莫迪因。

加载Disqus评论