AX & Azure Series: Redis Cache


The underlying data structure for AX is gigantic, as many of us have become intimately aware.  As such, performance tuning is always something on the mind of those who administer the ERP system.  Better performance = better experience for your end users. 

One great way to help with performance is caching.  AX 2012 has a lot of options for caching, including Entire Table caching, record level caching, and the SysGlobalObjectCache or SGOC for short.

As stated on MSDN, the SGOC works well in cases where records are selected repeatedly – such as master data, parameters, anything that is relatively static.  The values can be retrieved from memory instead of making an extra call to the database.

One deficiency in the SGOC is that it is only available for users on that same AOS.  Often several AOS are deployed as part of a cluster to provide redundancy and help performance by distributing workload across several servers. Ironic how one method of improving performance can hinder another!

Another alternative is to use the Azure Redis cache. It can be used by all AOS in a cluster, as well as other applications that integrate with AX.

Redis supports the usual key/value pair, but also appending to strings, incrementing values in a hash, pushing to a list, among others.  It also has provisions for transactions, pub/sub, and keys with limited TTL lifespans.  Fun right? Let’s get started!

Head over to https://portal.azure.com/ and create a new Redis Cache:

After a few minutes this will be deployed a-la-cloud.  While it is getting set up, let’s create a new Visual Studio C# class library, I’m calling mine AzureRedis:


Add the StackExchange.Redis package to your project, and the corresponding namespace:

I’ve added a public constructor, and two helper methods to add key-value pairs and retrieve them from the cache.  You’ll see I am using an arbitrary key expiration of 25 minutes:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using StackExchange.Redis;
  6. using System.Threading;
  7.  
  8. namespace AzureRedis
  9. {
  10. public class CacheUtil
  11. {
  12. public ConnectionMultiplexer multiPlexer {get; set;}
  13. public String baseURI { get; set; }
  14. public IDatabase cache { get; set; }
  15.  
  16. public CacheUtil(String _uri, String _key)
  17. {
  18. if (!(String.IsNullOrEmpty(_uri)))
  19. {
  20. baseURI = _uri;
  21. multiPlexer = ConnectionMultiplexer.Connect(String.Format("{0},ssl=true,password={1}", _uri, _key));
  22. cache = multiPlexer.GetDatabase();
  23. }
  24. }
  25.  
  26. public bool addString(String _scope, String _key, String _value)
  27. {
  28. Boolean ret = false;
  29. String scopedKey = _scope + "#" + _key;
  30.  
  31. ret = cache.StringSet(scopedKey, _value, TimeSpan.FromMinutes(25));
  32. return ret;
  33. }
  34.  
  35. public String getString(String _scope, String _key)
  36. {
  37. String ret = String.Empty;
  38. String scopedKey = _scope + "#" + _key;
  39.  
  40. ret = cache.StringGet(scopedKey);
  41. return ret;
  42. }
  43. }
  44. }
  45.  
  46.  

Next, let’s add this project to the AOT and create a sample job to make sure things are working:

You’ll see we are connected to the Azure Redis cache. The possibilities are endless, and the cache can even persist while the AOS are cycled down for modelstore deployments.  Redis won't be a silver bullet for performance woes, but it has tremendous value if used appropriately.