`
xinlanzero
  • 浏览: 245895 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

将您的 Linux 应用程序迁移到 Amazon 云,第 3 部分: 实现可扩展性

 
阅读更多

简单地实现更大流量支持

Sean A. Walberg, 高级网络工程师

 

简介: 如果是连续阅读 本系列文章 至本文,您就知道我们已经将示例 Linux® 应用程序移植到云中了,此外我们还配置了一些基本的可靠性特性。本文是关于将应用程序移植到 Amazon 云中的系列文章的第 3 篇,是时候利用云的动态性的优势了,通过增加或减少基础架构来将静态资产加载和部署到云边界。

查看本系列更多内容

<!-- <p class="ibm-no-print"> <div id="dw-tag-this" class="ibm-no-print"></div> <div id="interestShow" class="ibm-no-print"></div> </p> -->

 

发布日期: 2010 年 10 月 25 日
级别: 中级 其他语言版本: 英文
访问情况 8240 次浏览
建议: 0 (添加评论) <!-- Rating_Area_Begin --><!-- Ensure that div id is based on input id and ends with -widget -->

1 star2 stars3 stars4 stars5 stars 平均分 (共 3 个评分 )
<script type="text/javascript"></script><!-- Rating_Area_End -->

 

<!-- dW_Summary_Area_END --><!-- CONTENT_BODY -->
<!-- MAIN_COLUMN_BEGIN -->
<!-- Related_Searches_Area_And_Overlays_Begin --><!-- MAIN_COLUMN_CONTAINER_BEGIN -->
<!-- MAIN_COLUMN_CONTENT_BEGIN -->

本系列文章的 将您的 Linux 应用程序迁移到 Amazon 云,第 1 部分:初始迁移 首先介绍了名为 SmallPayroll.ca 的软件即服务(Software as a Service)。这个应用程序被移植到 Amazon Elastic Compute Cloud (Amazon EC2)。然后,在 将您的应用移植到 Amazon 云,第 2 部分:提高应用的可靠性 中,我们通过增加冗余、备份和更可靠磁盘使这个应用程序变得更加健壮。

现在,我们是时候考虑稳定性之外的可扩展性。因为服务器是按小时租赁的,只在需要时才运行额外的服务器会有意义吗?异步处理作业呢?

内容分布式网络(CDN)将静态资产缓存到网络边缘,这在过去是非常昂贵的。即使非常小的网站也可以使用云计算创建的 CDN。使用 CDN 可以大大提升性能,所以让我们先实现这一步。

自动部署

实现动态扩展基础架构的一个关键原因是新实例可以在不需要人工干预的前提下部署到生产环境。在每一次修改后均不间断地重新绑定一个 Amazon Machine Instance (AMI) 都是可以实现的,如部署代码或修改数据库。然而,使用一些脚本就可以使服务器直接进行自动部署。

SmallPayroll.ca 的部署过程类似于其他的应用程序:

  1. 从知识库获取代码,如 Subversion 或 git。
  2. 启动应用程序服务器。
  3. 验证应用程序已正确启动。
  4. 将新的服务器添加到负载均衡池。

这个实例还必须在 /etc/hosts 上配置一个数据库服务器。

从知识库获取代码

SmallPayroll.ca 代码库是存储在一个 Subversion 知识库中的。Subversion 是一个源代码控制系统,它可以跟踪代码库的修改,允许开发人员创建新分支和在单独环境中合并特性开发代码。

最简单的情况是,一个 Rails 应用程序正好可以运行源代码的检出副本。修改后,生产服务器会执行一个更新,然后重新启动。名为 Capistrano 的 Ruby Gem 以一种支持集中控制多个服务器的方式来管理这些部署,而且如果发生问题,这种方式很容易回滚。

新的服务器可以引导 Capistrano 过程启动,而不需要手动检出代码。这需要事先做更多的操作,但是它意味着 Capistrano 之后可以更快速简单地管理这个服务器。清单 1 显示了 Capfile 的初始内容,这个文件位于购买产品用户的 home 目录下。


清单 1. 引导启动 Capistrano 部署的 Capfile
				
load 'deploy' 

# Where is the code? This will need to be customized!
set :repository,  "http://svn.smallpayroll.ca/svn/payroll/trunk/"
set :scm_username, "DEPLOY_USERNAME"
set :scm_password, "DEPLOY_PASSWORD"

# Deploy to the local server
server "localhost", :app, :web, :db, :primary => true

# By default Capistrano tries to do some things as root through sudo - disable this
set :use_sudo, false

# Define where everything goes
set :home, '/home/payroll'
set :deploy_to, "#{home}"
set :rails_env, "production"

这个 Capfile 是通过 cap 命令执行的。Capistrano 要求使用 Secure Shell (SSH) 连接一个服务器,即使在本地主机上也是一样。清单 2 是作为应用程序用户运行的,准备好了服务器,这样用程序用户就可以使用 SSH 连接到本地服务器,然后 Capistrano 任务就可以运行。


清单 2. 准备环境
				
# Create the SSH directory and generate a secure key pair
mkdir .ssh
chmod 700 .ssh
ssh-keygen -b 1024 -t dsa -q -f .ssh/id_dsa -N ""

# Allow the user to SSH in to the server without a password
cat .ssh/id_dsa.pub >> .ssh/authorized_keys
# SSH is very fussy about permissions! Nothing should be readable
# by other users
chmod 600 .ssh/*

# SSH in once, ignoring host keys, so that the server will save the host key
ssh 127.0.0.1 -o StrictHostKeyChecking=false /bin/false

清单 2 分为以下 3 部分:

  • 前两个命令会创建一个 SSH 目录,它只允许应用程序用户读取。第三个命令创建了一个 1024 位的 Digital Signature Algorithm (DSA) 密钥(-b 1024 -t dsa),关闭输出(-q),指定密钥的名称,在这里不指定密码。
  • 将用户的公钥复制到 authorized_keys 文件,这允许用户使用相应的密钥登录,而不需要使用密码。同时要保证其他人无法读取这个目录的文件。
  • 如果不保存主机密钥,SSH 和 Capistrano 会提示验证密钥,这会中断自动化部署过程。最后一个命令是忽略主机密钥而登录到本地服务器,然后运行 /bin/false。这样就可以保存主机密钥。

这个过程的最后一步是创建环境,并部署应用程序当前版本。清单 3 说明了如何使用 Capistrano 处理这些任务。


清单 3. 使用 Capistrano 部署应用程序
				
cap deploy:setup
chmod 700 /home/payroll
cap deploy

清单 3 运行了 deploy:setup 任务,它会在应用程序的 home 目录下创建出目录结构,这个目录结构由名为 sharedreleases 的目录构成。每一个部署在 releases 文件夹下有自己的一个目录。而 shared 目录是用于保存日志和其他可能在各个部署间共享的元素。

在部署这个应用程序之前,第二个命令会将 home 目录的权限修改为 700。如果安装程序开放这个部署目录的权限,允许组成员写入,那么这个部件会被部署到 home 目录,而不是它的子目录。如果除应用程序用户以外还有人能够修改 home 目录,那么 SSH 守护进程就不支持基于密钥的认证。

最后运行的是 deploy 任务,它会从 Subversion 检出代码,并将代码保存到 release 目录,然后创建一个名为 current 的符号链接(symlink)。有了这个符号链接及每一个位于单独目录的部署,应用程序就可以轻松回滚到之前的版本。


自动启动应用程序服务器

即使我们能够创建一个在负载增大时会自动增加更多 Web 服务器的系统,但是这并不总是一个好的做法。Web 流量的波动是非常大的,所以您可能希望保证流量在启动另一个服务器之前停下来。您大约需要 10 分钟才能确定所遇到的负载是否需要一个新服务器,然后还需要在 5 到 10 分钟后才能启动一个实例,从而在池中创建一个新的 Web 服务器。这个过程可能对于 Web 服务器不可行的,但是它对于工作服务器仍然是有效的。

您仍然可以定期扩大或缩小您的应用程序服务器。例如,SmallPayroll.ca 应用程序的大多数用户会在每周工作日的 8:00 a.m. 到 9:00 p.m. 之间到达。为了改进注册用户的响应时间并减少服务器开销,在 8:00 a.m. 到 9:00 p.m. 这段时间会运行三个服务器,而在其他时间则运行两个服务器。这个部署脚本已经写好:您所需要的就是启动服务器,并将它添加到负载均衡器上。

从 cron 启动服务器

cron 工具仍然是使额外实例按预设方案启动或关闭的天然场所。理想的 crontab 类似于清单 4 所示。


清单 4. 一个自动启动和关闭服务器的 crontab
				
0  8 * * 1-5 $BASEDIR/servercontrol launch app
0 21 * * 1-5 $BASEDIR/servercontrol terminate app

您需要在虚拟环境以外的一个主机上的用户 crontab 中输入清单 4 的代码。在星期一到星期五的 8:00 a.m.,脚本 servercontrol 会执行带有参数 launch app 的命令。而在 9:00 p.m.,它会使用参数 terminate app。这个脚本将这些参数解析为操作和服务器角色。现在,这些角色总是为 app

编写控制脚本

然后,下一步是编写服务器控制脚本,这个脚本是从 cron 执行的,并根据要求启动服务器。清单 5 显示的是这个脚本的代码。


清单 5. servercontrol 脚本
				
#!/bin/bash

AMI=ami-ad7e95c4
OP=$1
ROLE=$2

if [ "$OP" == "" -o "$ROLE" == "" ]; then
  echo You\'re doing it wrong.
  echo $0 operation number role
  exit
fi

case "$OP" in
  "launch")

    # Launch the instance and parse the data to get the instance ID
    DATA=`ec2-run-instances -k main -d "DB=10.126.17.1;ROLE=$ROLE" $AMI`
    INSTANCE=`echo $DATA | grep INSTANCE  | cut -f 6 -d ' '`
    echo $INSTANCE is your instance

    # Keep on checking until the state is "running"
    STATE=""
    while [ "$STATE" != "running" ]; do
      STATE=`ec2-describe-instances  $INSTANCE |awk '/^INSTANCE/ {print $6}'`
      echo the state is $STATE
      sleep 10
    done
    # Keep track of which instances were started by this method
    echo $INSTANCE >> $HOME/.ec2-$ROLE

    # Now that the instance is running, grab the IP address
    IP=`ec2-describe-instances $INSTANCE |awk '/^INSTANCE/ {print $13}'`

    # If this is to be an app server...
    if [ "$ROLE" == "app" ]; then
      # Check the web server to make sure it returns our content
      UP=0
      while [ $UP -eq 0 ]; do
        OUTPUT=`curl -s -m 5 http://$IP`
        if [ $? -eq 0 ]; then # curl was successful
          echo $OUTPUT | grep -qi 'welcome'
          if [ $? -eq 0 ]; then
            UP=1
          else
            sleep 5
          fi
        fi
      done

      # Register with the load balancer
      elb-register-instances-with-lb smallpayroll-http --instances $INSTANCE
    fi

  ;;

  "terminate")
     # Grab the instance ID. It's the last line of the file
     FILE=.ec2-$ROLE

     # Assuming the file exists, of course
     if [ ! -f $FILE ]; then
        echo No dynamic instances have been started for the $ROLE role
        exit
     fi

     # The last instance started is the last line of the file
     INSTANCE=`tail -1 $HOME/.ec2-$ROLE`

     # Assuming there's something in that file, that is
     if [ "$INSTANCE" == "" ]; then
         echo No dynamic instances have been started for the $ROLE role
         exit
     fi

     # Terminate the instance
     ec2-terminate-instances $INSTANCE

     # Take the instance out of the load balancer
     elb-deregister-instances-from-lb smallpayroll-http --instances $INSTANCE

     # Delete the last line of the file
     sed -i '$d' $FILE
  ;;

  *)
      echo "You may only launch or terminate"
      exit
  ;;
esac

这个脚本比较长,但是它有很多代码是用于错误处理的。这个脚本在开头解析参数,将 launchterminate 函数调用放到 case 语句中。在 launch 函数中,这个脚本启动了一个实例,并等待这个实例进入 running 状态。然后脚本会获取这个实例的 IP 地址,并等待服务器的一个 Web 请求成功返回包含 welcome 的页面。

停止这个实例是非常简单的。实例 ID 已经被写到用户 home 目录下的一个 dotfile 中,其中较新的实例 ID 会依次被附加到文件后面的。为了停止这个实例,脚本会读取文件的最后几行来获取最近启动的实例 ID,发出一个停止命令,将实例从负载均衡器删除,然后删除文件中包含这些实例的最后几行内容。

注意,每一个角色都拥有它自己的文件。现在只有 Web 角色,但是将来还会有更多的角色。

清单 5 中比较奇怪的一项是 -d 参数,它会被传递给 ec2-run-instances。这个参数包含了实例访问一个只允许本实例访问的 URI 结果信息。这个信息是用一个字符串表示的。在清单 5 中,服务器的角色和数据库服务器都会传递给这个实例。

编写 init 脚本

init 脚本是在系统启动时运行的,它会在实例上配置一个当前版本的应用程序,同时启动对应的应用程序配置。清单 6 使用了来自控制脚本的信息来确定配置信息。清单中的这些代码可能是 SYSV 启动脚本的一部分,或者它可能位于启动时只运行一次的 rc.local 文件。


清单 6. 应用程序的 startup 脚本
				
USER=payroll
HOME=/home/payroll
SRC=/etc/smallpayroll

# If this is a fresh AMI, set up the application directories
if [ ! -d $HOME/releases ]; then
  echo "Setting up environment"
  cp $SRC/Capfile $HOME
  # Listing 2
  su - $USER -c "cd $HOME && sh $SRC/setup_environment"
fi

echo "Deploying the application"
su - $USER -c "cd $HOME && /opt/ree/bin/cap deploy"

# Grab the user supplied data. 169.254.169.254 returns data unique to the instance.
USER_DATA=`/usr/bin/curl -s http://169.254.169.254/2007-01-19/user-data`
DBHOST=`echo $USER_DATA | sed 's/.*DB=\([0-9\.]*\).*/\1/'`
ROLE=`echo $USER_DATA | sed 's/.*ROLE=\([a-zA-Z]*\).*/\1/'`
logger "Starting application with DBHOST=$DBHOST and ROLE=$ROLE"

# If available, put the dbhost in /etc/hosts
if [ "$DBHOST" != "" ]; then
  sed -i '/dbhost/d' /etc/hosts
  echo "$DBHOST dbhost" >> /etc/hosts
fi

# Depending on the role...
case "$ROLE" in
  'app')
    # Web server... start up mongrel
    su - $USER -c "mongrel_rails cluster::start \
      -C $HOME/current/config/mongrel_cluster.yml"
  ;;
  *)
    logger "$ROLE doesn't make sense to me"
  ;;
esac

清单 6 开头先初始化了一些变量。接下来,它会检查应用程序用户的 home 目录,查看 cap deploy:setup 任务之前是否已运行过;如果没有运行,那么这个任务就会运行。然后,它会运行一个部署操作,将最新代码部署到实例上。

现在,代码已经准备好了,该脚本会使用一些 sed 操作检查传递给这个实例的元数据,将组件保存到变量中。如果设置了 DBHOST 变量,那么它的值会被写入 /etc/hosts,这样应用程序就知道如何查找这个数据库。脚本也会检查服务器角色;如果这个服务器会成为一个应用程序服务器,那么相关的服务器也会被启动。

清单 5 和清单 6 中的代码相对较多,但它们设置了自动启动和停止任何类型服务器所需要做的操作。通过使用清单 4 的 crontab,附加服务器也会在高峰时间打开,然后在空闲时间关闭。接下来,您需要扩展这个框架来启动更多不同类型的服务器。


异步任务处理

使动态网站更加高效的一个常用技术是将一些运行时间很长的请求移到后台过程完成。这些运行时间很长的任务通常不像真实请求那样对处理时间有很高的要求。应用程序可能会使用 Asynchronous JavaScript + Extensible Markup Language (Ajax) 向任务处理系统发送一个请求,且在后台轮询完成。用户会看到一些等待图示,表示应用程序正在运行过程中,但是用户并不需要更复杂的过程来发送更多交互请求。

这种方法也一样要求使用足够的资源来处理这些任务。但是如果任务队列太长,用户会不愿意等待他们的报表完成。这似乎是一个动态服务器启动的理想情况。这些任务的运行会有专门的组件进行监控;如果运行负载超过一定的临界值,那么就会启动新的服务器来帮助解决问题。完成之后,这个服务器就会停止。

“没有免费的午餐”

运行新服务器并不是免费,所以当您决定要启动新服务器时,您需要考虑一些经济因素。

本系列文章所介绍的 m1.small 一小时或一小时内的花费大约为 8.5 美元。所以,如果您启动一个实例,哪怕只启动了一分钟,您也需要花费一个小时的费用。如果您决定使用更大的实例来完成更多操作,那么每小时的花费会增大。

您一定要理解启动和不启动一个新服务器的花费情况。较慢的服务意味着客户满意度下降。较快的服务则能够提高客户满意度,但是会增加成本。

后台处理是通过良好的 delayed_job gem 实现的 — 特别是,collectiveidea 分支(见 参考资料)。您可以在一行代码中使用这个 gem 清除所有任务和实现优先级队列,这样您的重要任务就不需要在例程作业后等待了。这个任务处理守护进程会耗尽 Rails 应用程序目录,并使用数据库来请求工作。这意味着您需要扩展当前的脚本,以处理 delayed_job 守护进程。

修改 init 脚本以支持任务处理服务器

在前面的 清单 6 中,脚本检查了它的实例元数据,以查看 servercontrol 脚本所传递的参数值。ROLE 参数表示服务器的任务,其中 app 表示一个应用程序服务器。每一个服务器类型的说明都封装在一个 case 语句中。清单 7 扩展了这个 case 语句,来处理 delayed_job 角色。


清单 7. 处理 delayed_job 服务器的启动
				
case "$ROLE" in
  'app')
    # For an application server, start the mongrels
    su - payroll -c "/opt/ree/bin/mongrel_rails cluster::start \
      -C /home/payroll/current/config/mongrel_cluster.yml"
  ;;
  'job')
    # For a job server, figure out what kind of machine this is, and run
    # an appropriate number of job processing daemons
    TYPE=`curl -s http://169.254.169.254/2007-08-29/meta-data/instance-type`
    case "$TYPE" in
      'm1.small') NUM=2 ;; # 2 per ECU * 1 ECU
      'm1.large') NUM=8 ;; # 2 per ECU * 4 ECUs
      *) NUM=2 ;;
    esac
    su - payroll -c "RAILS_ENV=production $HOME/current/script/delayed_job -n $NUM start"
  ;;
  *)
  logger "$ROLE doesn't make sense to me"
  ;;
esac

这个脚本会检查服务器的角色。如果这个服务器是一个应用程序服务器,那么脚本就会启动混合服务器。如果这个服务器只是一个作业服务器,那么脚本就会检查它运行在哪一个实例上。这些信息可以从另一个 169.254.169.254 虚拟主机的 URL 上获取。粗略地估计,这个脚本在每一个 Elastic Compute Unit(ECU) 期间会启动两个 delayed_job 工作者。您的工作负载会有所不同。

至此,servercontrol 脚本可以通过在命令行上输入 launch job 启动一个新的作业服务器。

监控队列

您有许多方法可以监控队列运行。您可以添加一个任务及其处理时间限制,如果时间超出了临界值就启动一个新服务器。这个方法的缺点是当队列真正恢复后,需要经过很长时间您才能确定它已经恢复。最简单的方法是查询数据库中未完成的请求数量,并将查询放到一个控制器中进行。清单 8 显示了这样一个控制器。


清单 8. 一个显示队列长度的控制器
				
class QueueController < ApplicationController
  def length
    render :text => Delayed::Job.count(
      :conditions => "priority > 0 AND failed_at IS NULL").to_s
  end
end

清单 8 显示了队列的长度 — 特别是,优先级大于 0 的任务和未处理的任务(不包括失败的任务)— 并直接显示这个数字,而不是将它传递到一个模板。浏览 /queue/length,您就可以知道当前的队列等待情况。

根据要求启动新的作业服务器

现在您可以很容易确定队列的长度,但是您还需要一个脚本来处理这个数据。清单 9 显示了这样一个脚本。


清单 9. 在需要时启动更多的作业服务器
				
#!/bin/bash

# What's the length of the queue
QUEUE=`curl -s http://app.smallpayroll.ca/queue/length`
# How many servers are running now? (zero out if file doesn't exist)
SERVERS=`wc -l $HOME/.ec2-job`
if [ "$SERVERS" == "" ]; then SERVERS=0; fi

# launch up to two servers while the queue is over 20
if [ $SERVERS -le 2 -a $QUEUE -gt 20 ]; then
  servercontrol launch job
fi

# Terminate one instance if the queue is under 5
if [ $SERVERS -gt 0 -a $QUEUE -lt 5 ]; then
  export TZ=/usr/share/zoneinfo/UTC 
  LAST=`tail -1 $HOME/.ec2-job`
  # But only if the server has run for at least 45 minutes
  UPTIME=`ec2-describe-instances $LAST | \
    awk '/INSTANCE/ {t=$10; gsub(/[\-:T\+]/, " ", t); print systime() - mktime(t) }'`
  if [ $UPTIME -gt 2700 ]; then
    servercontrol terminate job
  fi
fi

业务逻辑

清单 9 实现了一个简单的算法。它能够演示动态启动服务器的内在原则,但是它可以更加智能些。例如,这个脚本可以不停地观察队列的长度,然后在长度值稳定一段时间后关闭服务器,而不是使用像现在这样的判断方法。

清单 9 的代码应该在 cron 中每 5 分钟执行一次。它首先获取队列的长度,以及当前运行的作业服务器数。这个作业服务器数是从包含动态运行服务器实例 ID 的 .ec2-job 文件长度计算得来的。如果队列的长度超过 20,而且现在运行的服务器少于 2 个,那么就需要启动一个服务器。如果现在运行的服务器超过一个,而队列长度小于 5,那么这个脚本就需要进行更多的检查,以决定它是否应该停止一个实例。

这个脚本首先通过设置 TZ 环境变量将时区设置为 Coordinated Universal Time (UTC)。然后获取最后运行的作业服务器实例 ID,并查询启动时间。这个时间会进行某些 awk 替换,从而获得以秒为单位的服务器活动时间。如果服务器已在线超过 45 分钟,那么这个实例就可以关闭了。否则,这个服务器将继续运行。

这里设置的 45 分钟界限可以避免过早关闭服务器。如果队列减少,那么会有后续任务加入,这个服务器仍然运行。


使用一个内容分布式网络

当有人访问您的网站,他或她也会加载图像、Cascading Style Sheets (CSS) 和 JavaScript 代码。CDN 服务能够缓存静态资产,并将它们分布式地部署在许多互联网服务器上。这样,您就可以为用户实现更快速的静态资产访问,使他们能够同时下载多个文件。Amazon 提供了一个名为 Amazon CloudFront 的服务 — 与其他服务一样是按使用付费的。

由 CDN 挂载的资产是从另一个服务器请求的,所以请求的 URL 也是不一样的。例如,http://app.smallpayroll.ca/stylesheets/style.css 会从应用程序服务器加载样式表,而 http://cdn0.smallpayroll.ca/stylesheets/style.css 则是从 CDN 加载样式表。如果 CDN 上没有这个内容,那么它可以从原始 服务器获取内容,然后缓存并返回给用户。

CloudFront 与其他的 CDN 稍微有一些不同,因为它的原始服务器是一个 Amazon Simple Storage Service (Amazon S3) 存储区。要使用 CloudFront,您首先必须将静态资产存储到 Amazon S3 存储区中,然后把 URL 改为使用 CloudFront 主机。

创建 CloudFront

在 CloudFront 主页(见 参考资料 的链接),单击链接进行注册。您需要等待一个激活电子邮件到达后才能继续操作。

当您接收到激活的确认信息,您就可以在您的 Amazon Web Services 控制页面,单击 Amazon CloudFront 选项卡。您可以看到图 1 所示的页面。


图 1. CloudFront 发布控制面板
CloudFront 分配控制面板

注意,还没有创建发布。一个发布 指的仅仅是将会连接到一个 Amazon S3 存储区的一组文件。单击 Create Distribution 就可以到达如图 2 所示的页面。


图 2. 创建一个发布
创建一个发布

执行以下操作:

  1. Delivery Method 中选择 Download
  2. Origin 下拉列表中选择一个 Amazon S3 存储区,或者使用您的 Amazon S3 工具创建一个新存储区。
  3. Logging 中选择 Off;这表示您不需要使用这些日志。
  4. CNAMEs 域中输入 4 个子域名,例如从 cdn0.smallpayroll.cacdn3.smallpayroll.ca
  5. Comments 中输入一些备注信息。
  6. Distribution Status 选择 Enabled

单击 Create,您会回到 CloudFront 选项卡,这时您就可以看到刚刚创建的发布了(见图 3)。


图 3. 配置的一个发布
配置的一个发布

在这个页面上有一个域名,如 djdzxdmb99068.cloudfront.net。您现在必须到您的 DNS 服务器上配置这四个 CNAME,将它们指定对应发布的域名。Amazon Elastic Load Balancing 采用了类似的方式,只是它要求创建四个数字形式的名称。

在与这个发布相对应的 Amazon S3 存储区上创建一个测试文件。您就能够通过浏览这个发布的域名看到这个文件,如在浏览器访问 http://djdzxdmb99068.cloudfront.net/test.htm,可以查看到存储区中名为 test.htm 的文件。如果出现拒绝访问的错误,您需要确认这些文件开启了公共访问权限(具体的设置方法取决于您所使用的 Amazon S3 存储区管理工具)。如果上面这个测试通过,那么您就可以尝试使用之前创建的 CNAME,如 http://cdn1.smallpayroll.ca/test.htm。

同步文件

您必须将公共目录下的文件复制到 Amazon S3 原始存储区。最简单的方法是在 Rails 应用程序的根目录下运行以下命令:

s3sync.rb -r -p public/ smallpayroll-cdn:

-r 选项表示复制是递归的。-p 选项表示将所有文件设置为公开可读。

如果您希望自动地完成这个过程,请参考 参考资料 关于执行这个任务的 gem 链接。

修改您的应用程序

最简单的情况,您可以修改所有的图像、JavaScript 和 CSS 链接,将它们指向其中一个 CDN 链接,而不是 Web 服务器。如果您使用了诸如 image_tag 的 Rails URL 标签,那么您可以在 Rails 中实现这个操作。将下面一行代码添加到 config/environments/production.rb:

ActionController::Base.asset_host = "cdn%d.smallpayroll.ca"

这行代码添加了一行生产环境配置 — 静态资产保存在 asset_hosts 定义的主机上。%d 的默认值是 0 到 3,所以 Railes 会循环查询 cdn0.smallpayroll.ca、cdn1.smallpayroll.ca、cdn2.smallpayroll.ca 和 cdn3.smallpayroll.ca 来获取内容。这些都是您在 CloudFront 上配置的相同主机。通过这 4 个主机,您就可以支持在浏览器上同时下载 8 个资产,因为浏览器通常限制一次只向一个网站创建最多两个连接。

现在,您的应用程序将会使得 CDN。这时应用程序的访问速度会大大提升!


结束语

应用程序使用 Amazon CloudFront 作为一个 CDN 可以提高客户端下载速度并支持并行下载,从而大大提升页面加载速度。应用程序也可以修改为支持动态扩展和缩减计算资源。有一些启动和停止操作可以通过调度实现,而另外一些则可以根据负载自动进行。此外,有一些脚本可扩展用于处理更多的情况。

管理是之前缺少的一环。在任何时刻,您可能都无法知道到底有多少计算机在运行。部署还不是自动执行的,因为服务器清单总是在变化。您也还不知道这些服务器本身的运行状态是怎么样的。请阅读本系列的最后一篇文章,以了解这些问题的答案。

<!-- CMA ID: 556095 --><!-- Site ID: 10 --><!-- XSLT stylesheet used to transform this file: dw-article-6.0-beta.xsl -->

参考资料

学习

获得产品和技术

  • 现在您已经了解了几个 Amazon S3 的 AMI,您可能希望调整一些旧的 AMI。Amazon S3 File Manager 是一个基于 Web 的文件管理器,它与许多独立应用程序或浏览器插件有相似的特性。如果删除一个 AMI,请别忘记将它 ec2-deregister

  • S3Sync 是一个很有用的复制 Amazon S3 文件以及处理存储区的工具。

  • Capistrano 是一个流行的部署包,它的工作方式与 Rake 相似。

  • delayed_job 是一个后台作业服务器,它能够与 Rails 和 ActiveRecord 整合。这个是项目的 collectiveidea 分支的链接,它是当前维护的分支。

  • synch_s3_asset_host 是一个快速同步 Amazon S3 原始存储区和应用程序静态文件的 gem。

  • 以最适合您的方式 IBM 产品评估试用版软件:下载产品试用版,在线试用产品,在云环境下试用产品,或者在 IBM SOA Sandbox for People 中花几个小时来学习如何高效实现面向服务架构。

讨论

关于作者

从 1994 开始,Sean Walberg 就一直在学术、企业和 Internet 服务供应者环境中从事 Linux 和 UNIX 系统的研究。在过去几年里,他撰写了大量有关系统管理的文章。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics