如何提高您迁移的 Linux 应用程序的可靠性
本系列的 将您的 Linux 应用程序迁移到 Amazon 云,第 1 部分:初始迁移 介绍了如何将一个物理服务器迁移到一个物理云服务器中。尽管所有的工作都已完成,但是,应用程序并没有明显的改善,这主要是因为引入了更多的单点故障。
甚至在单个物理服务器上,您都有冗余电源、错误纠正 RAM、冗余磁盘和丰富的故障前诊断指示器监控。在一个云服务器上,您不知道您已经获取了什么 — 或者更确切地说,您不知道您访问了什么。云服务器通常是可靠的,但是采取预防措施是很明智的,特别是自从 Amazon 提供额外服务来提高可靠性之后。
当部署到一个云计算环境之后,最好做好有可能会丢失一个虚拟实例的准备。这不是说云服务是不可靠的,而是说您可能遇到的故障类型不像您在物理环境中所遇到的。因此您应该将智能性引入您的应用程序,处理通信损耗并在多个服务器之间实现伸缩性。不管您要构建什么类型的环境,这种思想将有助于您构建一个更好的应用程序。
在本文中,您将了解如何使用 Amazon Elastic Block Store (EBS) 改进数据库的短暂存储,您可以通过建立备份进一步提高数据保护功能。跨越多个实例进行负载均衡可防止应用程序服务器丢失,并允许您从各种故障中恢复。
图 1 展示了您上次中断的应用程序的架构。
所有对象都在一个 Amazon Elastic Compute Cloud (Amazon EC2) 实例上。前端 Web 服务器、nginx 、请求多个混合实例的代理或服务器静态文件本身。混合应用程序服务器在同一个主机上访问一个 PostgreSQL 数据库。
实例存储是 Amazon EC2 与 VMware 和 Xen 等虚拟化技术之间最大的不同。我们知道,一个 Amazon EC2 实例提供一个 10GB 的固定根分区和一个实例磁盘,后者的大小取决于启动的实例的类型。根分区是在启动时从 Amazon Machine Image (AMI) 克隆的,实例存储为空。当您关闭您的服务器时,您的实例存储丢失。
Amazon 的初始位置告诉人们应该频繁地备份他们的服务器到 Amazon Simple Storage Service (Amazon S3)。如果您的服务器崩溃,那么您应该有其他的服务器承受负载,或者您可以从 Amazon S3 获取数据。最终,Amazon 推出了 EBS,这是一个提供永久性磁盘的服务。如果您的服务器崩溃,您可以将 EBS 卷附加到另一个服务器上。Amazon 甚至构建一个快照来简化备份。
SmallPayroll 应用程序中数据库服务器的主要问题是一个单点故障。有两个常见的方法可以对其进行校正。一个是构建两个能够彼此接管的数据库;另一个是减少潜在停机时间让一切更为合理。第一种方法有最少的停机时间但是较为复杂,第二种方法在这种情况下更为实用。如果数据库服务器崩溃,将启动一个新的实例替换它。EBS 考虑了数据安全性。从错误发现到启动一个新数据库服务器并重新指向客户机总共用时应该低于 10 分钟。作为一点优势是,EBS 存储比起实例存储有一个较高的 I/O 容量。
要使用 EBS,应该执行以下步骤:
ec2-create-volume
命令创建卷。ec2-attach-volume
命令将卷附加到一个正在运行的实例中。 建立 EBS 的第一步是通知 Amazon 您想要创建一个卷。您需要知道两件事:您的镜像的大小(千兆字节为单位)和您想要在其中使用镜像的可用性区域。可用性区域 的概念是 Amazon 提出的,用来描述服务器的位置。以 us-east 开始的区域是在北维吉尼亚州,统称为地区。此时,在 us-east 地区有 3 个这样的区域:us-east-1a、us-east-1b 和 us-east-1c。每一个可用性区域设计的目的是隔离其他可用性区域中的故障。同一地区的区域彼此仍然很接近,因此它们是低延迟的。
EBS 的一个限制是卷只能挂载到创建它所在的可用性区域中。有办法可以移动它们,但是您必须在同一可用性区域中创建您的卷作为服务器。
运行命令:
ec2-create-volume -s 20 -z us-east-1a |
在 us-east-1a 区域创建一个 20GB 的卷。如果您不知道您的服务器在哪,ec2-describe-instances
命令将会告诉您。您可以对 ec2-run-instance
使用 -z
参数来指定您的服务器启动的位置。清单 1 显示了这个命令以及输出。
$ ec2-create-volume -s 20 -z us-east-1a VOLUME vol-c8791ca1 20 us-east-1a creating 2010-07-01T02:52:52+0000 |
清单 1 的输出显示了创建的卷以及卷的 ID 为 vol-c8791ca1
。了解这一点,您就可以将卷附加到一个正在运行的 Amazon EC2 实例中,前提是您要知道服务器的实例标识符以及将卷作为服务器的设备。运行命令:
ec2-attach-volume vol-c8701ca1 -i i-fd15e097 -d /dev/sdj |
将这个最新创建的卷附加到服务器实例 i-fd15e097
。记住,您可以通过 ec2-describe-instances
命令找到您的实例标识符,并可使用 ec2-describe-volumes
查看卷列表。
现在,您的虚拟服务器有了一个名为 /dev/sdj 的磁盘,像查看普通磁盘那样查看它。对于任何一个磁盘,您需要在原始磁盘上创建一个文件系统。根据需要,您可以有不同的选择:
即使 RAID 和 LVM 提供了有趣的特性,对于一个相对较小的 EBS 卷来说 XFS 也是最简单的选择。您将可以使用 XFS 的冻结特性以及 EBS 快照来进行一致的备份。清单 2 列出了如何创建一个 XFS 文件系统并将其挂载到主机上。
# mkfs.xfs /dev/sdj meta-data=/dev/sdj isize=256 agcount=8, agsize=32768 blks = sectsz=512 attr=0 data = bsize=4096 blocks=262144, imaxpct=25 = sunit=0 swidth=0 blks, unwritten=1 naming =version 2 bsize=4096 log =internal log bsize=4096 blocks=2560, version=1 = sectsz=512 sunit=0 blks, lazy-count=0 realtime =none extsz=4096 blocks=0, rtextents=0 # mkdir /ebsvol # mount /dev/sdj /ebsvol |
清单 2 运行 mkfs.xfs
命令来格式化 /dev/sdj。(如果没有 mkfs.xfs
,命令运行 gem install -y xfsprogs
。)该命令的输出描述了文件系统的参数。只要输出中没有错误,这些参数可以忽略。清单 2 中最后两个命令创建一个名为 /ebsvol 的挂载点,然后在挂载点挂载文件系统。
文件系统现在是可用的。即使服务器出现故障,/ebsvol 之下的任何文件都将持续保留。
您已经在 /ebsvol 上挂载了一个 EBS 卷,需要将 PostgreSQL 数据移入。最直接的方法是复制现有的数据存储,并使用一个符号链接进行修正。尽管这个技术很不错,但是一个更简洁的选择是从 EBS 卷克隆数据到 /var/lib/pgsql。清单 3 显示了这一操作程序。
# service postgresql stop # mv /var/lib/pgsql /ebsvol # mkdir /var/lib/pgsql # chown postgres:postgres /var/lib/pgsql # mount /ebsvol/pgsql /var/lib/pgsql -o bind # service postgresql start |
清单 3 中的一系列命令功能如下:
mount
的 bind
选项挂载 /ebsvol/pgsql on top of /var/lib/pgsql。 mount
的 bind
选项将第一个目录克隆到第二个。一个目录中的改变将会在另一个中出现 — 毕竟,它是同一磁盘上的同一个块。使用 bind
与对同一设备进行两次挂载的区别在于,您就可以挂载子目录而无需挂载整个文件系统。
如果您的服务器崩溃了,执行以下步骤:
ec2-attach-volume
附加 EBS 卷到实例。 如果您最近已经打包了您的 AMI,您的数据库系统将是最新的。
云计算的一个优势是您很容易访问服务器容量。目前,SmallPayroll.ca 环境在同一虚拟实例中同时有数据库和应用程序服务器,这同迁移到 Amazon EC2 之前是一样的。下一步是从数据库服务器中分离应用程序服务器。
术语扩展性 通常是与容量联系在一起的。如果说一个应用程序可扩展,就是说应用程序可以增长空间来应对更多用户负载。如果通过添加服务器实现扩展性,则称为横向扩展。如果用一个更大的服务器替换现有服务器来应对负载,则该应用程序是纵向扩展 的。
您可以结合使用横向和纵向扩展。使用较大的服务器和运行速度更快的磁盘更易于处理超出数据库容量的问题,且更易于 跨服务器分散计算。纵向扩展和横向扩展大部分是应用程序设计的一个功能。一些应用程序不能跨计算机分散,不管计算机有多快,这些操作都需要花费很多的时间。而且,一些应用程序可能会横向扩展到一定点,在该点,一个瓶颈会使添加数据库后应得的边际收益荡然无存。
当您跨越多个服务器分散应用程序时,问题出现了,即如何分配输入更新。进行这一操作最常用的设备是一个负载均衡器,这是一个从外部接收请求并将它们移交给下一个可用应用程序服务器的装置。因为这不是一个密集任务,一个设备就能处理大量连接,软件中也可处理这一功能。
Amazon EC2 提供一个云计算负载均衡器,称为 Elastic Load Balancing,在大多数场合都适用。它分配请求,可通过一个 API 重新配置为添加或删除服务器,并在后端服务器上执行常规检查。
另一个使用 Elastic Load Balancing 的方法是在一个 Amazon EC2 实例上运行您自己的负载均衡软件,比如 HAProxy 或 Varnish(更多信息见 参考资料 链接)。这个过程比起使用 Elastic Load 更复杂,但是可以对流量提供更高级别的控制。Elastic Load Balancing 适用于 SmallPayroll.ca 这类应用程序。
图 2 显示了 SmallPayroll.ca 应用程序的新设计。
输入请求停留在 Elastic Load Balancing 上,并被发送给两个服务器之一。服务器本身运行 nginx,来处理静态请求并将任何动态请求委托给混合实例。混合实例附加到一个数据库服务器上。
如果一个应用程序服务器无法运行,Elastic Load Balancing 将所有流量转向另一个服务器。
为了构建独立的应用程序服务器,您需要启动两个以上的实例。您可以像前面那样使用相同的 AMI,因为它拥有所需的全部软件。一次可以启动多个实例:清单 4 显示了如何使用同一个命令启动两个实例。
$ ec2-run-instances ami-147f977d -k main -z us-east-1a \ -d 'role=web,db=10.201.207.180' -n 2 RESERVATION r-9cc240f7 223410055806 default INSTANCE i-81ee2eeb ami-147f977d pending main ... INSTANCE i-87ee2eed ami-147f977d pending main ... |
ec2-run-instances
命令类似于过去所用的命令。使用 -z us-east-1a
可以选择可用性区域,因为数据库服务器是在同一地区。此时,您需要将数据库和应用程序服务器保持在同一可用性区域,来减少延迟和带宽消耗。
然而,-d
和 -n
参数是新的。-n 2
参数只是通知 Amazon 启动两个实例,这在输出中经过确认。-d
参数可以向实例传递信息。清单 5 源自新实例,显示了如何检索这些信息。
[root@domU-12-31-39-0C-C5-B2 ~]# DATA=`curl -s http://169.254.169.254/latest/user-data` [root@domU-12-31-39-0C-C5-B2 ~]# echo $DATA role=web,db=10.201.207.180 |
curl
命令从含有用户数据的 Amazon EC2 服务检索一个 Web 页。这类似于在 将您的 Linux 应用程序迁移到 Amazon 云,第 1 部分:初始迁移 中服务器检索其 Secure Shell (SSH) 键的方法。
在应用程序服务器上几乎不需要进行任何设置,因为它们是从 AMI 克隆的,AMI 能够根据本地数据库运行应用程序。Rails 应用程序从 config/database.yml 中读取其数据库配置,告知应用程序将要使用的数据库。默认情况下,应用程序连接到本地主机。
首先,通过向 /etc/hosts 添加一个条目来创建一个 DNS 别名。例如,10.201.207.180 dbserver
将别名 dbserver 赋给地址 10.201.207.180。使用数据库的私有地址是很重要的,这是分配给 eth0 的地址,而不是您连接的公共地址。在同一个可用性区域中 Amazon EC2 实例私有地址之间的通信是免费的,但是从一个 Amazon EC2 实例到另一个实例的公共地址的通信是要付费的。
接下来,添加您的 database.yml 文件,将您的应用程序指向之前创建的 DNS 别名,清单 6 显示了这个配置。
production: adapter: postgresql encoding: utf8 database: payroll_prod pool: 5 username: payroll password: secret host: dbserver |
您可以启动您的 Rails 应用程序,通过应用程序服务器的公共 IP 地址连接它。如果出现一个错误,检查下列内容:
listen_addresses="*"
这样一行。 弹性负载均衡器是一个比较简单的负载均衡器。请求进入负载均衡器,然后被转发到池中一个可用的服务器中。弹性负载均衡可以进行一些基础的 Web 服务器状况检查,来避免将请求发送到出现故障的服务器。它也有一些基本的关联性机制可以让您维护同一后端服务器上的用户。还有一些高级特性,比如根据 URL 重新定向,目前还不受支持。
配置 Elastic Load Balancing 有三个步骤:
清单 7 显示了正在运行中的前两个步骤。
$ elb-create-lb smallpayroll-http \ --listener "lb-port=80,instance-port=80,protocol=HTTP" \ --availability-zones us-east-1a DNS_NAME DNS_NAME DNS_NAME smallpayroll-http-706414765.us-east-1.elb.amazonaws.com $ elb-configure-healthcheck smallpayroll-http --target "HTTP:80/" \ --interval 30 --timeout 3 --unhealthy-threshold 2 --healthy-threshold 2 HEALTH_CHECK TARGET INTERVAL TIMEOUT HEALTHY_THRESHOLD UNHEALTHY_THRESHOLD HEALTH_CHECK HTTP:80/ 30 3 2 2 |
清单 7 显示了两个命令,第一个命令 elb-create-lb
,创建负载均衡器。第一个参数是负载均衡器的名称,对您来说是惟一的。--listener
参数声明面向公众的端口是 80,它也被连接到实例中的 80 端口。所用的协议是 HTTP。该命令的输出是一个 DNS 名称 — 这里是 smallpayroll-http-706414765.us-east-1.elb.amazonaws.com。和大多数负载均衡器不一样的是,它不为您提供要连接到的公共 IP 地址。Amazon 指定自己的 IP 地址,然后您可以通过一个 DNS 别名进行连接。
第二个命令是 elb-configure-healthcheck
,它首先引用负载均衡器名称,然后指定根据 HTTP 协议在端口 80 上使用根 URL 进行正常检查。也可以写入一个独立的控制器和动作来进行检查,比如 /status,但是在这里,根 URL 可以保证应用程序正常运行。
第二行参数依次指定以下操作:
--interval 30
。每 30 秒测试一次。--timeout 3
。如果测试没有失败,应用程序要等待多长时间才能有回应。 --unhealthy-threshold 2
。如果连续有两个测试失败,将服务器标记为非服务状态。 --healthy-threshold 2
。 一个失败服务需要连续两次成功检测,服务器才能返回池中。下一步是将实例附加到负载均衡器(见清单 8 )。您可以随意添加和删除实例。
$ elb-register-instances-with-lb smallpayroll-http --instances i-87f232ed,i-85f232ef INSTANCE_ID INSTANCE_ID INSTANCE_ID i-85f232ef INSTANCE_ID i-87f232ed $ elb-describe-instance-health smallpayroll-http --headers INSTANCE_ID INSTANCE_ID STATE DESCRIPTION REASON-CODE INSTANCE_ID i-85f232ef InService N/A N/A INSTANCE_ID i-87f232ed InService N/A N/A |
清单 8 首先展示的是添加到 smallpayroll-http
负载均衡器中的两个实例。运行 elb-describe-instance-health
命令查看池中每个服务器的状态。InService
意味着服务器能够通过负载均衡器处理请求。
最后,浏览您的负载均衡器的 DNS 名称。您应该看到应用程序在跨越两个服务器运行。为了使负载均衡器以您的应用程序真实 DNS 名工作,将您应用程序 DNS 记录从 A
修改为指向负载均衡器 DNS 名的 CNAME
。关于 DNS 需求的更多信息见 参考资料,其中包括一些附加说明。尽管 DNS 方法是笨重的,但它允许您处理大量请求,比起您在 Amazon EC2 实例中通过构建一个负载均衡器处理的请求增加了几个数量级。DNS 修改可以随时进行,因为这不会中断服务。
应用程序现在分布在两个节点上,可在少于半小时内从头开始启动数据库服务器。这对可用性是有好处的,但如果管理员无意中销毁了关键数据或者 EBS 卷发生故障,这就不能发挥作用了。幸好,针对这些问题已经有解决方案了。
EBS 提供快照功能,可以在 Amazon S3 中存储卷的副本。确切地说,EBS 快照存储的是与上次快照的差异。数据库使问题复杂化,因为它缓存了一些磁盘写操作,这可能会生成一个不一致的快照。因此,您必须确保磁盘上的一切都保持一致的状态(见清单 9)。备份次序如下:
尽管这一过程可能需要一到两分钟,但是 Amazon 将快照暂时存储到后台 Amazon S3 中。第 3 步后进行的修改将在快照中反映出来。
#!/bin/sh export EC2_HOME=/usr/local/ export JAVA_HOME=/usr export EC2_CERT="/root/.ec2/cert.pem" export EC2_PRIVATE_KEY="/root/.ec2/pk.pem" echo "select pg_start_backup('snapshot')" | su - postgres -c psql /usr/sbin/xfs_freeze -f /ebsvol/ /usr/local/bin/ec2-create-snapshot vol-93f77ffa --description "`date`" /usr/sbin/xfs_freeze -u /ebsvol/ echo "select pg_stop_backup('snapshot')" | su - postgres -c psql |
您可以使用 ec2-describe-snapshots
命令验证快照状态,如清单 10 所示。
$ ec2-describe-snapshots --headers SnapshotId VolumeId Status StartTime SNAPSHOT snap-298cb741 vol-93f77ffa completed 2010-06-29T02:50:55 SNAPSHOT snap-a2b959c9 vol-93f77ffa completed 2010-07-13T15:14:54 |
清单 10 显示了两个已完成的快照及其时间。
通过从 cron
中运行 清单 9 中的代码可以自动创建快照。您也可以使用 ec2-delete-snapshot
命令定期整理您的快照列表。
如果您的 EBS 卷发生故障或者要从 EBS 恢复旧数据,就需要从最近的快照中恢复。恢复一个 EBS 卷的过程同创建一个新卷大致一样。清单 11 显示了如何从 清单 10 中恢复上一个快照。
$ ec2-create-volume --snapshot snap-a2b959c9 -z us-east-1a -s 20 VOLUME vol-d06b06b9 20 snap-a2b959c9 us-east-1a creating |
然后将这个卷挂载到任何实例中来恢复您的数据。
从您的服务器备份文件的一个简单方法是将它们复制到 Amazon S3 或者将它们作为您库存 AMI 的一部分。对于二进制文件和存储包,第二个方法更为有效,而复制到 Amazon S3 常用于用户数据。S3Sync
工具提供一些命令行 Amazon S3 工具以及一个轻巧的 rsync
型实用工具。
下载 S3Sync 实用工具(链接见 参考资料)。清单 12 显示了如何创建 bucket 用于备份,以及如何上传文件到 Amazon S3。
$ s3cmd.rb createbucket smallpayroll-backup $ s3cmd.rb listbuckets ertw.com smallpayroll-backup $ s3sync.rb -r /var/uploads smallpayroll-backup:`date +%Y-%m-%d` $ s3cmd.rb list smallpayroll-backup:2010-07-12 -------------------- 2010-07-12/uploads 2010-07-12/uploads/file1.txt |
清单 12 首先创建一个名为 smallpayroll-backup 的 bucket,您可以在一个 bucket 中存储不同时间的不同备份,而只需要执行该步骤一次。第二个命令验证 bucket 是否已创建;您可以查看刚刚创建的 bucket 和 AMI 驻留在其中的 ertw.com bucket 。
s3sync.rb
命令将 /var/uploads 目录递归复制到备份 bucket 中,用当前日期作为所有文件的前缀。最后一个命令显示了 bucket 内的所有文件。
恢复文件其实也很简单,您可以使用有预留参数的 S3Sync
,也可以通过另一个工具,比如 Amazon S3 File Manager(见 参考资料),检索单个文件。
SmallPayroll 应用程序正在云中运行,而且其设计更适合未来增长。尽管硬件平均故障时间没有改变,做足备份和脚本工作可确保数据是安全的,您可以根据需要快速重建环境。
原来直接迁移到云计算的许多弊端已经解决了。尽管环境的健康可见度很低,但是对于扩展服务器资源来满足需求是很有帮助的,这些问题将在本系列的下两篇文章中解决。
<!-- CMA ID: 512809 --><!-- Site ID: 10 --><!-- XSLT stylesheet used to transform this file: dw-article-6.0-beta.xsl -->学习
CNAME
来将您的应用程序别名设为 Amazon 主机名。获得产品和技术
ec2-deregister
处理。 S3Sync
是一个很有用的工具,用来向 Amazon S3 来回复制文件,以及操作您的 bucket。 讨论