Using the Windows Azure Content Delivery Network

By caching static content on the Content Delivery Network CDN, the web server can offload the serving of content that doesn't change, and so will have more resources for processing requests for active content. Browser-based users of your application will get static content delivered with less latency from a server that is closer to them.

Windows Azure is a very rich platform. Next to compute and storage, it offers a series of building blocks that simplify your life as a cloud developer. One of these building blocks is the content delivery network (CDN), which can be used for offloading content to a globally distributed network of servers, ensuring faster throughput to your end users.

Reasons for using a CDN

There are a number of reasons to use a CDN. One of the obvious reasons lies in the nature of the CDN itself: a CDN is globally distributed and caches static content on edge nodes, closer to the end user. If a user accesses your web application and some of the files are cached on the CDN, the end user will download those files directly from the CDN, experiencing less latency in their request.

1644-CDN1.png

Another reason for using the CDN is throughput. If you look at a typical webpage, about 20% of it is HTML which was dynamically rendered based on the user’s request. The other 80% goes to static files like images, CSS, JavaScript, and so forth. Your server has to read those static files from disk and write them on the response stream, both actions which take away some of the resources available on your virtual machine. By moving static content to the CDN, your virtual machine will have more capacity available for generating dynamic content.

Enabling the Windows Azure CDN

The Windows Azure CDN is built for two services that are available in your subscription: storage and compute. The easiest way to get started with the CDN is by using the Windows Azure Management Portal at https://azure.microsoft.com/en-us/. If you have a storage account or a hosted service on Windows Azure, you can navigate to the “Hosted Services, Storage Accounts & CDN” pane and click the “CDN” node. After selecting a storage account or hosted service, click the “New Endpoint” button in the toolbar, which will show you the following screen:

1644-CDN2.png

If required, you can enable HTTPS on the CDN edge nodes. Unfortunately, this is done using a certificate that Microsoft provides and there’s currently no option to use your own. A second option available is to enable caching based on query string parameters. When enabled, the CDN will keep different cached versions of files hosted on your storage account, based on the exact URL (including query string) for that file.

After clicking OK, the CDN will be initialized. This may take up to 60 minutes because the settings you’ve just applied may take that long to propagate to all CDN edge locations, globally. Your CDN will be assigned a URL in the form of http://<id>.vo.msecnd.net. You can also assign a custom domain name to the CDN by clicking the “Add Domain” button in the toolbar.

Serving blob storage content through the CDN

Let’s start and offload our static content (CSS, images, JavaScript) to the Windows Azure CDN using a storage account as the source for CDN content. In an ASP.NET MVC 3 project, edit the _Layout.cshtml view and change the URLs to all referenced scripts and CSS to a URL hosted on your newly created CDN:

Note that the CDN URL includes a reference to a blob container names “static”.

If you now run this application, you’ll find no CSS or JavaScript applied, as you can see in the picture below. The reason for this is obvious: we have specified the URL to our CDN but haven’t uploaded any files to our storage account backing the CDN.

1644-CDN3.png

Uploading files to the CDN is easy. All you need is a public blob container and some blobs hosted in there. You can use tools like Cerebrata’s Cloud Storage Studio or upload the files from code. For example, I’ve created an action method taking care of uploading static content for me:

Note the lines of code marked in red. The first one, container.SetPermissions, ensures that the blob storage container we’re uploading to allows public access. The Windows Azure CDN can only cache blobs stored in public containers.

The line of code,  blob.Properties.CacheControl, is more interesting. How does the Windows azure CDN know how long a blob should be cached on each edge node? By default, each blob will be cached for 72 hours. This has some important consequences. First, you cannot invalidate the cache and you have to wait for content expiration to occur. Second, the CDN will possibly refresh your blob every 72 hours.

As a general best practice, make sure that you specify the Cache-Control HTTP header for every blob you want to have cached on the CDN. If you want to have the option to update content every hour, make sure you specify a low TTL of, say, 3600 seconds. If you want less traffic to occur between the CDN and your storage account, specify a longer TTL of a few days or even a few weeks.

Another best practice is to address CDN URLs using a version number. Since the CDN can, when enabled, create a separate cache of a blob based on the query string, appending a version number to the URL may make it easier to refresh contents in the CDN based on the version of your application. For example, main.css?v1 and main.css?v2 may return different versions of main.css cached on the CDN edge node. Here’s a quick code snippet which appends the AssemblyVersion to the CDN URLs:

Using hosted services with the CDN

So far we’ve seen how you can offload static content to the Windows Azure CDN. We can upload blobs to a storage account and have them cached on different edge nodes around the globe. Did you know you can also use your hosted service as a source for files cached on the CDN? The only thing to do is, again, go to the Windows Azure Management Portal and ensure the CDN is enabled for the hosted service you want to use.

Serving static content through the CDN

The main difference with using a storage account as the source for the CDN is that the CDN will look into the /cdn/* folder on your hosted service to retrieve its contents.  There are two options for doing this: either move static content to the /cdn folder, or use IIS URL rewriting to “fake” a /cdn folder.

Using both approaches, you’ll have to modify the _Layout.cshtml file to reflect your CDN URL:

Note that this time the CDN URL does not include any reference to a blob container.

Moving static content into a /cdn folder

The Windows Azure CDN only looks at the /cdn folder as a source of files to cache. This means that if you simply copy your static content into the /cdn folder as seen in the below image, you’re finished. Your web application and the CDN will play happily together.

1644-CDN4.png

Using IIS URL rewriting to expose static content to the CDN

An alternative to copying static content to a /cdn folder explicitly is to use IIS URL rewriting. IIS URL rewriting is enabled on Windows Azure by default and can be configured to translate a /cdn URL to a /URL. For example, if the CDN requests the /cdn/styles/main.css file, IIS URL rewriting will simply serve the /styles/main.css file leaving you with no additional work.

To configure IIS URL rewriting, add a <rewrite> section under the <system.webServer> section in Web.config:

As a side note, you can also configure an outbound rule in IIS URL rewriting to automatically modify your HTML into using the Windows Azure CDN. Do know that this option is only supported when not using dynamic content compression and adds additional workload to your web server due to having to parse and modify your outgoing HTML.

Serving dynamic content through the CDN

Some dynamic content is static in a sense. For example, generating an image on the server or generating a PDF report based on the same inputs. Why would you generate those files over and over again? This kind of content is a perfect candidate to cache on the CDN as well!

Imagine you have an ASP.NET MVC action method which generates an image based on a given string. For every different string the output would be different, however if someone uses the same input string the image being generated would be exactly the same.

As an example, we’ll be using this action method in a view to display the page title as an image. Here’s the view’s Razor code:

In the previous section, we’ve seen how an IIS rewrite rule can map all incoming requests from the CDN. The same rule can be applied here: if the CDN requests /cdn/Home/GenerateImage/Welcome, IIS will rewrite this to /Home/GenerateImage/Welcome and render the image once and cache it on the CDN from then on.

As mentioned earlier, a best practice is to specify the Cache-Control HTTP header. This can be done in your action method by using the [OutputCache] attribute, specifying the time-to-live in seconds:

We would now only have to generate this image once for every different string requested. The Windows Azure CDN will take care of all intermediate caching.

Note that if you’re using some dynamic bundling of CSS and JavaScript like ASP.NET MVC4’s new “bundling and minification”, those minified bundles can also be cached on the CDN using a similar approach.

Conclusion

The Windows Azure CDN is one of the building blocks to create fault-tolerant, reliable, and fast applications running on Windows Azure. By caching static content on the CDN, the web server has more resources available to process other requests, and users will experience faster loading of your applications because content is delivered from a server closer to their location.