Saturday, September 13, 2014

Game-development Log (5. CDN Caching for map tiles)


The map that was displayed on my previous post was using an Azure Web-Site to render the tiles. On this iteration I've included a CDN so that the tiles are cached and the latency is minimal when serving them.

Generically speaking this is my target architecture including a CDN:

  1. The map displayed on the browser requests a tile to the CDN
  2. The CDN checks if it contains the image or not
  3. If not, it queries the tile-server for that particular image
  4. The Tile Server generates it as described on my previous post
  5. The CDN stores the image tile 
  6. The CDN returns the image to the browser
So, here's the recipe on how to setup this on Azure:

1. Create a Cloud-Service instead of a Web-Site for the Tile-Server

First, why a cloud-service and not a web-site? Basically a limitation on Azure CDN itself:

"The origin domain is the location from which the CDN caches content. The origin domain can be either a storage account or a cloud service;"

Anyway, not really fond of Cloud-Services but in my particular case it might be a blessing in disguise, especially as I'm generating tiles with GDI+ and I might want to try using other technologies that require installing stuff on the server, which you simply can't do with Web-Sites.

Regardless, publishing a Web-API to a Cloud-Service is incredibly easy inside Visual Studio 2013. Just follow these steps (taken from

I've published it as "tilewin" and it now appears properly on my Azure Management Portal

To validate that it's working just open the url:

2. Create a new "cdn" route on the tile-server webapi

This is an interesting one. According to Azure documentation to have a Cloud-Service be used as pull-origin for CDN it has to provide a "/cdn" route.

"Can I use different folder names in the Windows Azure CDN?
For hosted-service object delivery as of SDK 1.4, you are restricted to publishing under the /cdn folder root on your service." (

Also, if you recall, a tile-request was something in the likes of:

Simply adding a "/cdn" at the beginning of the route won't work. Thus, it will need to receive the params through query-string. So, I'm trying to support a route such as:

Fortunately with WebAPI 2.0 this is a breeze. First I've defined the new action as:
public async Task<VectorTile> GetTile([FromUri]int z,[FromUri]int x,[FromUri]int y)
    var tile = await _tileLoader.LoadVectorTileAsync(z, x, y);
    if (tile == null)
        throw new HttpResponseException(HttpStatusCode.NotFound);
    return tile;
Also, to support the "type" parameter I had to change my MediaTypeMappings to include QueryStringMapping:
var imageFormatter = new TileImageFormatter((ITileGenerator)config

        .Add(new UriPathExtensionMapping(
        "png", new MediaTypeHeaderValue("image/png")));

        new QueryStringMapping(
        "type", "png", new MediaTypeHeaderValue("image/png")));


Afterwards I re-published the Cloud Service and the following url now works:

3. Create and configure the Azure CDN

I've created a new CDN entry specifying the Cloud Service as the origin and making sure that Query String is enabled.

Now issuing a request for the CDN (without including the "/cdn" on the url) returns an image tile:

I've already made a simple performance comparison on obtaining the tile directly from the Cloud-Service vs CDN. The latency on the CDN one is awesome (as expected). Also, I had setup Output cache on the Cloud-Service. Otherwise the difference would be even greater.

So, now ready to setup the map.

4. Change the Map to use the CDN

Now that's the easy one. I've just replaced the URL from{z}/{x}/{y}.png

No comments:

Post a Comment