Fri, 11 Mar 2011

Using the Windows Azure CDN for Your Web Application

The Windows Azure Content Delivery Network has been available for more than a year now as a way to cache and deliver content from Windows Azure blob storage with low latency around the globe. Earlier this week, we announced support in the CDN for caching web content from any Windows Azure application, which means you can get these same benefits for your web application.

To try out this new functionality, I built an application last night: http://smarxcdn.cloudapp.net. It fetches web pages and renders them as thumbnail images. (Yes, most of this code is from http://webcapture.cloudapp.net, which I’ve blogged about previously.) This application is a perfect candidate for caching:

  1. The content is expensive to produce. Fetching a web page and rendering it can take a few seconds each time.
  2. The content can’t be precomputed. The number of web pages is practically infinite, and there’s no way to predict which ones will be requested (and when).
  3. The content changes relatively slowly. Most web pages don’t change second by second, so it’s okay to serve up an old thumbnail. (In my app, I chose five minutes as the threshold for how old was acceptable.)

I could have cached the data at the application level, with IIS’s output caching capabilities or Windows Azure AppFabric Caching, but caching with the CDN means the data is cached and served from dozens of locations around the globe. This means lower latency for users of the application. (It also means that many requests won’t even hit my web servers, which means I need fewer instances of my web role.)

The Result

You can try a side-by-side comparison with your own URLs at http://smarxcdn.cloudapp.net, but just by viewing this blog post, you’ve tested the application. The image below comes from http://az25399.vo.msecnd.net/?url=blog.smarx.com:

thumbnail of blog.smarx.com

If you see the current time in the overlay, it means the image was just generated when you viewed the page. If you see an older time, up to five minutes, that means you’re viewing a cached image from the Windows Azure CDN. You can try reloading the page to see what happens, or go play with http://smarxcdn.cloudapp.net.

Setting up a CDN Endpoint

Adding a Windows Azure CDN endpoint to your application takes just a few clicks in the Windows Azure portal. I’ve created a screencast to show you exactly how to do this (also at http://qcast.it/pXhWH):

The Code

To take advantage of the Windows Azure CDN, your application needs to do two things:

  1. Serve the appropriate content under the /cdn path, because that’s what the CDN endpoint maps to. (e.g., http://az25399.vo.msecnd.net/?url=blog.smarx.com maps to http://smarxcdn.cloudapp.net/cdn/?url=blog.smarx.com.)
  2. Send the content with the correct cache control headers. (e.g., Images from my application are served with a Content-Cache header value of public, max-age=300, which allows caching for up to five minutes.)

To meet the first requirement, I used routing in my ASP.NET MVC 3 application to map /cdn URLs to the desired controller and action:

routes.MapRoute(
    "CDN",
    "cdn",
    new { controller = "Webpage", action = "Fetch" }
);

To meet the second requirement, the correct headers are set in the controller:

public ActionResult Fetch()
{
    Response.Cache.SetCacheability(HttpCacheability.Public);
    Response.Cache.SetMaxAge(TimeSpan.FromMinutes(5));
    return new FileStreamResult(GetThumbnail(Request.QueryString["url"]), "image/png");
}

The two Response.Cache lines are what set the Cache-Control header on the response. You can also use web.config to set cache control headers on static content.

[UPDATE 3:37pm] David Aiken pointed out that there’s a better way to get this header emitted in ASP.NET MVC 3. This code seems to be approximately equivalent to what I wrote originally. Thanks, David!

[OutputCache(Duration=300, Location=OutputCacheLocation.Any)]
public ActionResult Fetch()
{
    return new FileStreamResult(GetThumbnail(Request.QueryString["url"]), "image/png");
}

Download

You can download the full source code for http://smarxcdn.cloudapp.net here: http://cdn.blog.smarx.com/files/smarxcdn_source.zip. Note that I have not included CutyCapt.exe, which is required for creating the thumbnails. You can get CutyCapt here. Also note that my CDN URL is hardcoded in this solution, so be sure to change that if you’re building your own application.

Side Note

This application uses ASP.NET MVC 3. Having already made use of several techniques for installing ASP.NET MVC 3 in Windows Azure, I decided it was time for a new one. This code includes curl, and uses that to download the ASP.NET MVC 3 installer before running it.