This is the online documentation for PostSharp 5.0.
Download PDF or CHM. Go to v4.3 or v5.0

Synchronizing Local In-Memory Caches for Multiple Servers

Caching in distributed applications can be a tricky problem. When there are several instances of an application running simultaneously (typically web sites or web services deployed into the cloud or web farms), you have to make sure that the cache is properly invalidated for all instances of the application.

A typical answer to this issue is to use a centralized cache server (or a cluster of cache servers) that solves this problem for you. For instance, you can use a Redis server or a Redis cluster. However, running a cache server, even more a cache cluster, comes with a cost, and it does not always pay off for medium applications such as the website of a small business.

An alternative solution to the problem of distributed caching is to have a local in-memory cache in each instance in the application. Instead of using a shared distributed cache, each application instance caches its own data into its own local cache. However, when one instance of the application modifies a piece of data, it needs to make sure that all instances remove the relevant items from their local cache. This is called distributed cache invalidation. It can be achieved easily and cheaply with a publish/subscribe (Pub/Sub) message bus such as Azure Service Bus, much less expensive than a cache cluster.

PostSharp allows you to easily add sub/sub cache invalidation to your existing PostSharp caching.

The principal inconvenience of pub/sub invalidation is that there is some latency in the invalidation mechanism, i.e. different instances of the application can see different data during a few dozens of milliseconds.

This topic contains the following sections:

Using Azure Service Bus pub/sub for distributed invalidation

To use Azure Service Bus pub/sub for distributed invalidation:

  1. Add in-memory local caching to your application as described in Using In-Memory Cache.

  2. Go to a Microsoft Azure portal, open the Service Bus panel and create a new Topic. Choose a small value for the time-to-live setting, for instance 30 seconds. See Microsoft Azure website for details.

  3. In the Microsoft Azure portal, create a Shared access policy and include the Manage right. This policy will be used by your application.

  4. Go to the properties of the newly created policy and copy the primary or secondary connection string to the clipboard.

  5. Go back to your source code and find the place where the MemoryCachingBackend is initialized.

  6. Create an instance of AzureCacheInvalidatorOptions class and specify the connection string to the shared access policy you just created.

  7. Create an instance of the AzureCacheInvalidator class using the AzureCacheInvalidator.Create(CachingBackend, AzureCacheInvalidatorOptions) factory method passing the existing instance of theMemoryCachingBackend and AzureCacheInvalidatorOptions. Assign the new AzureCacheInvalidator the to CachingServices.DefaultBackend property.

Example

This example shows how to initialize an in-memory caching backend to let it invalidate and be invalidated using Azure Service Bus Pub/Sub.

C#
var localCache = new MemoryCachingBackend();

string connectionString = "Endpoint=sb://yourServiceNamespace.servicebus.windows.net/;EntityPath=yourTopic;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=yourKey";

var azureCacheInvalidatorOptions = new AzureCacheInvalidatorOptions
                                    {
                                        ConnectionString = connectionString
                                    };

CachingServices.DefaultBackend = AzureCacheInvalidator.Create( localCache, azureCacheInvalidatorOptions );
Using Redis pub/sub for distributed invalidation

If you are already using Redis for PostSharp caching, it is useless to add another layer of invalidation because this is already taken care of by the RedisCachingBackend class. However, if you already have a Redis cluster but you don't want to use it for caching, you can still use it for cache invalidation. An example situation is when the latency of your Redis server is too high for caching but sufficient for cache invalidation.

To use Redis Pub/Sub for distributed invalidation:

  1. Add in-memory local caching to your application as described in Using In-Memory Cache.

  2. Create an instance of StackExchange.Redis.ConnectionMultiplexer. See Redis Pub/Sub documentation for details.

  3. Create and configure an instance of RedisCacheInvalidatorOptions class.

  4. Create an instance of the RedisCacheInvalidator class using the RedisCacheInvalidator.Create(CachingBackend, IConnectionMultiplexer, RedisCacheInvalidatorOptions) factory method passing your instance of MemoryCachingBackend and RedisCacheInvalidatorOptions. Assign the instance to the CachingServices.DefaultBackend property.

Example

This example shows how to initialize an in-memory caching backend to let it invalidate and be invalidated using Redis Pub/Sub.

C#
var localCache = new MemoryCachingBackend();

string connectionConfiguration = "localhost";
string channelName = "myCahnnel";

ConnectionMultiplexer connection = ConnectionMultiplexer.Connect( connectionConfiguration );

var redisCacheInvalidatorOptions = new RedisCacheInvalidatorOptions
                                    {
                                        ChannelName = channelName
                                    };

CachingServices.DefaultBackend = RedisCacheInvalidator.Create( localCache, connection, redisCacheInvalidatorOptions );