Friday, February 4, 2011

Speeding up your site's assets with CloudFront

Moved here

As part of one of our regular performance passes on Avvo, we decided to give Amazon's CloudFront service a try to speed up the delivery of our images, css, and javascript. CloudFront is the CDN part of Amazon's Web Services suite, and as such, it replicates requested data it across Amazon's CloudFront servers distributed across the world.

By default, Amazon requires you to host anything distributed through CloudFront using S3, and S3 is the only option available through the web interface when configuring CloudFront. At first, this didn't seem like it would be an issue, but after trying to push our assets to S3 and hit them through CloudFront, we began to notice some problems.

Issues with using S3 as a backing store

It started with the slowness. Uploading our new assets to S3 on every deploy only took about a minute, but even a minute represents a significant portion of our total deploy time. Annoying, but still acceptable. What was less acceptable was the inablity for CloudFront and S3 to respond to clients' Accept-Encoding: gzip headers and automatically return the pre-gzip'd files we uploaded. Although there were ways to get around this issue, it was at this point that we decided to try Amazon's less-documented and less-accessible Custom Origins feature to tell CloudFront to use our site itself as its backing store. This, we hoped, would fix both the speed and gzipping issues, as well as be simpler to maintain.

Using Custom Origins

Custom Origins, although less accessible through Amazon's tools than S3 origins, seem to offer a much simpler solution for integrating CloudFront for assets that aren't already on S3. Fortunately, a few of the third-party Amazon Web Services tools already provide support for setting up a CloudFront distribution with Custom Origins. If your curl-fu is better than mine, you can hit their server directly by sending requests documented by Amazon. I prefer Ruby, though, so I tried out the newest version of RightScale's right_aws gem.

Installing RightAWS

(As far as I can tell, the right_aws gem available with gem install doesn't yet support custom origins. You can skip this part once it does).

Installing the gem was pretty easy using git and bundler:

git clone https://github.com/rightscale/right_aws.git
cd right_aws
bundle install

Of course, you could also build and install the gem yourself, if you prefer.

Setting up your Custom Origin

Once right_aws is installed, it's easy to write a script or start an irb session to set up a new CloudFront distribution:

require 'right_aws'
acf = RightAws::AcfInterface.new('aws public key', 'aws secret key')
acf.create_distribution(
  :comment => "My Remote Origin",
  :custom_origin => {
    :dns_name => "www.myserver.com",
    :http_port => 80,
    :https_port => 443,
    :origin_protocol_policy => 'match-viewer',
  },
  :enabled => true
)

The only tricky part of the above is the origin_protocol_policy parameter. This parameter can take one of two values, http-only or match-viewer. This specifies whether https requests to CloudFront assets will make https requests to your custom origin. Amazon suggests that http-only should be used unless there's a particular reason to use match-viewer.

At this point, you should be able to see your new distribution in the CloudFront console and hit your assets through the host they give you. There's still some more work to do to make sure your assets are delivered as quickly as possible, but that's another post that'll be written another time.

No comments: