Windows Azure: In-Memory Distributed Cache

Most recently, Microsoft presented a large service pack for the Windows Azure platform. The list of innovations included the long-awaited update of Windows Azure Caching. Previously, the developer faced some difficulties when working with a distributed caching system - the cache worked very slowly. Since Windows Azure stored cache data on separate servers, it took about 30-100 ms to request a data sample , which is not permissible for a system that speeds up data access.
So what has changed in the caching system?
Microsoft decided to keep up with its competitors and added support for In-Memory Caching. Now the data is stored not on a separate server, but in the server’s RAM and, accordingly, access to the data occurs instantly. Let's try to implement a new cache and compare the speed of work with the old one using ASP.NET MVC 3 (C #) as an example.

Caching provider

To access the cache, we need a provider. To implement the provider, create an interface for it with the necessary methods:
public interface ICacheProvider
    {
        void RemoveFromCache(string key); 
        T GetFromMethod(string cacheKey, TimeSpan cacheDuration, Func method); 
        T GetFromMethod(string cacheKey, Func method);
    }

The first method, obviously, deletes the object from the cache by key, the rest receive (add if there is no cache) data with the key and period set.

The next step is to implement the provider itself. The installation process for Windows Azure SDK 1.7 is not described here, it is understood that the developer has all the necessary libraries and components for development under Windows Azure.

We note several key points to consider when implementing the provider:
  • The cache does not have full cleaning functionality, so you need to provide for the possibility of invalidating old data when releasing updates;
  • Write to the cache can produce only one thread, in order to avoid errors;
  • Windows Azure Caching is not free functionality, so you need to reduce cache access to a minimum.

The provider itself will look like this:


 public class AzureCacheProvider : ICacheProvider
        {
            //Необходимо для инвалидации старого кэша при новом релизе
            private readonly string _prefix = StaticHelper.GetCurrentVersion();
            private readonly object _locker = new object();
            private readonly DataCache _cache;
            public AzureCacheProvider()
            {
                lock (_locker)
                {
                    {
                        var factory = new DataCacheFactory();
                        _cache = factory.GetDefaultCache();
                    }
                }
            }
            private void RemoveFromCache(string key, DataCache cache)
            {
                lock (_locker)
                {
                    cache.Remove(_prefix + key);
                    HttpContext.Current.Items.Remove(_prefix + key);
                }
            }
            private T GetFromCache(string key, TimeSpan expiration, Func method, DataCache cache)
            {
                object cacheItem = HttpContext.Current.Items[_prefix + key];
                if (cacheItem == null)
                {
                    cacheItem = cache.Get(_prefix + key);
                    if (cacheItem != null)
                        HttpContext.Current.Items[_prefix + key] = cacheItem;
                }
                if (cacheItem == null)
                {
                    lock (_locker)
                    {
                        cacheItem = cache.Get(_prefix + key);
                        if (cacheItem == null)
                        {
                            cacheItem = method();
                            if (cacheItem != null)
                            {
                                HttpContext.Current.Items[_prefix + key] = cacheItem;
                                cache.Put(_prefix + key, cacheItem, expiration);
                            }
                        }
                    }
                }
                return (T)cacheItem;
            }
            public void RemoveFromCache(string key)
            {
                RemoveFromCache(key, _cache);
            }
            public T GetFromMethod(string cacheKey, TimeSpan expirationSeconds, Func method)
            {
                return GetFromCache(cacheKey, expirationSeconds, method, _cache);
            }
            public T GetFromMethod(string cacheKey, Func method)
            {
                return GetFromMethod(cacheKey, TimeSpan.FromMinutes(15), method);
            }
        }


HttpContext.Current.Items here it is used to store in memory objects already received in the current request from the cache, in case of repeated access to data.

Role configuration

After writing the provider, you need to configure the cache. In SDK 1.7, a new Caching tab has been added to the role properties.

image

On this tab you need to enable cache support (Enable Caching) and set the amount of allocated memory for our data (for example: Co-located Role: Cache Size 30%)

Web.config

The final preparation will be the addition of new sections to Web.config. If there is no section at the very beginning of the file configSections, then you need to add it. Then put the following code inside:


At the end of Web.config, add a section description dataCacheClients:


This completes the configuration of Windows Azure Caching. Let's move on to a health check.

Cache testing


To test the cache, create a simple page that will cache the current time:

Cache test

Before: <%=DateTime.Now.Millisecond%> ms
<%=Facade.Instance.Cache.GetFromMethod("currentTime", () => DateTime.Now)%>
After: <%=DateTime.Now.Millisecond%> ms
<%using(Html.BeginForm("ClearCache","Admin"))%> <%{%> <%}%>

Facade.Instance.Cachein the code above is an instance of an object AzureCacheProvider obtained using IoC.
The action ClearCachelooks quite simple:


 public ActionResult ClearCache()
        {
            Facade.Instance.Cache.RemoveFromCache("currentTime");
            return View("admin");
        }

results


After compiling the project and launching the page in the cloud, we see the following result: When the page is first opened, an entry is added to the cache, which in this example takes about 16 ms. The next time the page is refreshed, the result is as follows: Fetching data from the new In-Memory Distributed Cache takes less than 1ms. By speed, this cache is not inferior to InProc cache.

Cache test
Before: 553 ms
6/10/2012 11:09:40 AM
After: 569 ms




Cache test
Before: 508 ms
6/10/2012 11:09:40 AM
After: 508 ms




As it was before?


To find out how it was before, you need to roll back the SDK to version 1.6 and make a small modification to Web.config. Replace section dataCacheClientswith:


After compiling the project and the opening of the test page we can see the following results: Ie 29 ms for adding entries to the cache and after updating the page: 32 ms for retrieving entries from the cache.

Cache test
Before: 521 ms
6/10/2012 11:09:40 AM
After: 550 ms




Cache test
Before: 501 ms
6/10/2012 11:09:40 AM
After: 533 ms




Total


Microsoft’s latest innovation has resolved one of the major problems with Windows Azure — the distributed caching problem. Now you can use the distributed cache without fear for a drop in application performance, and those who used other tools for this inside the Azure cloud can return to the functionality provided by the Windows Azure API.

Also popular now: