Update: This has been a fairly popular post. I did another one a couple of months ago which goes into the cache at a deeper level and highlights some different setup gotchas. You can view here the issues you may have with the Azure Co-Located Cache 1.7 and other caching gems.

One of the biggest gripes with the pricing model thus far has been the distributed cache – it’s expensive. We’ve been waiting for a while now to see the alternative and it arrived this week in the form of a distributed in-memory cache between role instances.

I wouldn’t normally write about this but today I’m taking the time to look into the features which we’ll be using in one of several projects we have for clients and our own usage pattern as well for our HPC workload product.

Anyway, let’s learn to build a simple ASP.NET web app using the new Cache Preview. I’ve tested the principles in this blog post on both “dedicated cache roles” (worker roles which come as a template in VS.NET) and web roles in ASP.NET which can allocate a share of their memory to a cache. I tested everything on two small web roles so 1.75 GB RAM @ 30% of available memory dedicated to the cache so each of the machines had over 0.5 GB in available cache.

Anyway, let’s learn by images.

Step 1: Create a Visual Studio cloud service project.

Choosing a cloud project

Choosing a cloud project

Step 2: Add a worker role using VS.NET template

Choosing a Role
Step 3: Configure the Cache in your web role in the dedicated role.
Configuring the Cache

Configuring the Cache

Things to note about this image. It’s all good and tests well in Azure without any problems but can be very volatile locally. One of the issues I had when trying to run the emulator is that CacheInstaller.exe failed with a TypeLoadException followed by a MissingMethodException. Since I saw this work the day before on Scott Gu’s machine I figured it must be something to do with my build. Anyway, I decompiled the executable and found out that it reflecting and loading another assembly and failing to extract the type. Checked again through a cascade of registry reads, realised it was loading a GAC assembly. When I cross-checked I realised that this was part of Windows Server AppFabric. I didn’t need this installed so uninstalled it and my emulated cache worked fine after that

When you follow the enablement steps above for the Cache Preview you should see that there are a couple of of touch points with .csdef. The first one involves the installation of a new plugin for Caching.


<Import moduleName="Caching" />

And the second one is an added LocalStorage resource.


<LocalResources>

<LocalStorage name="Microsoft.WindowsAzure.Plugins.Caching.FileStore" sizeInMB="1000" cleanOnRoleRecycle="false" />

</LocalResources>

Next add caching support by selecting the appropriate nuget package. This will save you a lot of time and you won’t need to munge any .config. Note well here… The official docs suggest using “Windows Azure Caching Preview” as a search string but I didn’t have any luck with that and in the images they show it looks they have this on a seperate package source. Use “Microsoft.WindowsAzure.Caching” as the search string and you’ll find it straight away.

Add Caching support from nuget

Add Caching support from nuget

The following additional assemblies should now be added:

  • Microsoft.ApplicationServer.Caching.AzureClientHelper
  • Microsoft.ApplicationServer.Caching.AzureCommon
  • Microsoft.ApplicationServer.Caching.Client
  • Microsoft.ApplicationServer.Caching.Core
  • Microsoft.Web.DistributedCache
  • Microsoft.WindowsFabric.Common
  • Microsoft.WindowsFabric.Data.Common

As you can see when you use cache configuration in the cloud project you have the option of sticking with the default cache or using a named cache. In this instance I’ve used an “azurecoder” named instance which I’ll be able to reference in both my code and config later.

Explicitly naming a cache

Explicitly naming a cache

In our cloud config file everything is fairly explicit and we get the same sense of control as we would with an ASP.NET cache in that we can apply LRU (Least RecentlyUsed) eviction policy to cache items, absolute or sliding window expiry timeouts etc.

One nice thing which Scott Gu referred to on the meetwindowsazure night is the high availability aspect of the cache. You can create backup copies of a particular named cache which will allow you to create backups of all of the cache data across one or more additional nodes in the role. This can simply be achieved by adding a number in the backfield field which is less the number of available role instances.

It’s also important to make sure that the config in the ASP.NET web.config which the nuget package added is updated. The identifier attribute of the autodiscover element must refer to the name of the role. If this is wrong in any way and you either forget about it and leave the “[replace here]” marker text or have a spelling mistake it will blow up when you try to use this with ASP.NET. Out of the box you can replace both the default ASP.NET session provider and the Output Cache by adding this as a provider and naming the cache we’re using (in our case “azurecoder”) explicitly.


<dataCacheClients>

<tracing sinkType="DiagnosticSink" traceLevel="Error" />

<dataCacheClient name="azurecoder">

<autoDiscover isEnabled="true" identifier="CacheRole" />

</dataCacheClient>

</dataCacheClients>

If like me, you make lots of silly mistakes and your role instance cycles round you may identify this new gem of a message where the fabric tries to find other named instance to form the distributed cache. Don’t panic if you’ve seen exceptions like this before with Velocity and AppFabric server this is purely an effect not a cause!


Microsoft.Fabric.Common.OperationCompletedException: Operation completed with an exception ---&gt; Microsoft.Fabric.Federation.RoutingException: The target node explicitly aborted the operation --- End of inner exception stack trace --- at Microsoft.Fabric.Common.OperationContext.End() at Microsoft.Fabric.Federation.FederationSite.EndRoutedSendReceive(IAsyncResult ar) at Microsoft.Fabric.Data.ReliableServiceManager.EndRefreshLookupTable(IAsyncResult ar)

So here is a small application I’ve written to illustrate how powerful and out-of-the-box this Cache Preview concept is. I have a couple of very simple views in an MVC project with each of the roles using 30% or so available memory as cache. The index view creates a random 14 character string as a key and places this with the machine name as a value into the cache. I create a region and set a tag so that I can search all of the tags and get back a list I can enuemrate through (since I’m not storing the cache keys between requests).


const string Elastaregion = "ElastaRegion";

public ActionResult Index()         {

var factory = new DataCacheFactory();

DataCache defaultCache = factory.GetDefaultCache();

DataCache cache = factory.GetCache("azurecoder");

var regions = cache.GetSystemRegions();

if (!(regions.Count() != 0 && regions.Contains(Elastaregion)))             {

cache.CreateRegion(Elastaregion);

}

var random = new RandomAccountName();

var key = random.GetPureRandomValue();

var tag = new DataCacheTag("azure");

cache.Put(key, Environment.MachineName, new[] { tag }, Elastaregion);

ViewBag.CacheItem = "Adding " + key + " for machine name " + Environment.MachineName;

return View();

}

Then we can simply display a list of all of the items as needed in a seperate view.


public ActionResult Items()         {

var factory = new DataCacheFactory();

DataCache cache = factory.GetCache("azurecoder");

IEnumerable<KeyValuePair<string, object>> coll = cache.GetObjectsByAnyTag(new[] { new DataCacheTag("azure") }, Elastaregion);

return View(coll);

}

The result is that we can look at the output and see that some of the cache items were placed in the cache from one machine or the other but they are available on both – despite the fact that they are not necessarily replicated on both unless the backup property has been specified (oops just noticed the grammar mistake!).

Output from ASP.NET

Output from ASP.NET

Have fun with this!

About these ads