Click here to Skip to main content
12,819,619 members (35,572 online)
Click here to Skip to main content
Add your own
alternative version


40 bookmarked
Posted 22 May 2009

Distributed Cache - Simplified

, 22 May 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
Cache mechanism is one of the basic infrastructures in every medium & above project, either web application or winForm application.

Following the Google search engine or advertising in technology sites or magazines, we can easily find a lot of sophisticated solutions for caching.
I found/know: MemCached, NCache, ScaleOut StateServer,
Shared Cache & even a Microsoft's implementation named Velocity.

Sometimes these solutions are the best thing for your project, they have a lot of bells and whistles, they were written by professionals who dedicated a lot of thought in all sorts of cache situations (or states..) & some of them already proved themselves in production environment - So why invent the wheel?
If you think about it...cache is really simple - at least the basics, so why not take full control?

Cache mechanism is one of the basic infrastructures in every medium & above project, either web application or winForm application.
The main goal of caching is to save roundtrips, from client to server, from application server to database server & in some cases from web server to application server.
The last one (web server to application server) is mainly used in web-sites to save HTML result of common queries instead of redirecting these again & again to the application.
In this article, I will concentrate on the other two.

In every application, there are lookup tables (mainly to fill combo-boxes with list of values), decision tables and other static or semi-static tables, these tables are read again & again whenever a form in the application containing them is opened and/or the application flow needs its values - these roundtrips from client to server & from application server to database are a waste of resources that could be saved if you save these in the client's & application server's memory.

As first step, you need to decide how far you can go with this.

  1. Which static tables are commonly used?
  2. How big are they? (memory on server & client are not endless...).
  3. What kind of access is needed to these tables? (if you search a lot in these tables using joins, it won't be very efficient to cache them).
  4. If these tables are tables that the user can update, how critical is it to refresh them & if so - how often is sufficient?

The answers to these questions are different in every application, but the main guidelines are to cache most (if not all) small static tables that are used in the application & never to cache big tables, tables that are updated often or tables that you can't 'live' with the fact that you're querying an old snapshot of the real one (I'm talking about a few seconds old..).
You are left with the question what is the limit of medium tables (in size) & what is often updated - as said before these change from application to application.

So let's start building...

We'll start with the database:

  1. sysApplicationServers table: This table will function as a registration table, every application server on load will 'register' itself here and will unregister itself when unloaded. Columns: IpAddress, FromDate.
  2. CacheItemQueue table: This table will contain tables needed for refresh.
  3. trig[table name]Cache trigger: Every dynamic & cached table will have a trigger, this trigger will add a row in CacheItemQueue for every sysApplicationServers row (on insert, update & delete).

For example: We have two application servers registered in sysApplicationServers, when we update users table, the result of the trigger is a simple insert with the result:

Table, IpAddress, FromDate
Users, appServer1IP, now
Users, appServer2IP, now

So this simple mechanism will 'let us know' when a table is modified so we can refresh it in memory snapshot (the insert will insert a new row only if there is no existing row for the same table+server combination).

Next, we'll write a thread that will sample CacheItemQueue table in the required interval, this thread will run in an endless loop from application load.
When it identifies a new table for it to load, it loads and deletes this row from cacheItemQueue.

    CacheListenerThread cacheListenerThread = new CacheListenerThread();
    thread = new Thread(cacheListenerThread.RunListener);
    while (true)
public void RefreshCache()
    string ipAddress = BasicUtil.GetLocalIp();
    SqlCommand command = new SqlCommand("spCache_AsyncTablesLoader");
    DatabaseManager.AddSqlParameter(command, "@ipAddress", ipAddress);

The actual cache can be built using ASP.NET which has a nice implementation, I chose Microsoft's Enterprise library to allow the cache to work also under a non web application server (in my case Windows service).

Cache manager interface explains itself:

public interface ICacheManager
    object Get(string key);
    bool Add(string key, object value);
    bool Contains(string key);
    void LoadDataTable(string tableName);

LoadDataTable method will allow us to maintain cache tables that are loaded only on first use or reloaded if needed.

I mainly use this infrastructure to contain all sorts of dataTables but as you can see, it's built to contain any object & also cache stuff with expiration date/time.
The Server implementation of cache manager:

using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;

    public class ServerCache : ICacheManager
        public delegate bool LoadDataTableDelegate(string tableName);

        private static ServerCache serverCacheManager;
        private CacheManager cacheManager;

        private event LoadDataTableDelegate loadDataTableEvent;

        private ServerCache()
                cacheManager = CacheFactory.GetCacheManager();
            catch (Exception ex)
                throw new ApplicationException("Failed to initilize cache manager", ex);

        public static void InitCache(LoadDataTableDelegate loadDataTable)
            serverCacheManager = new ServerCache();
            serverCacheManager.loadDataTableEvent += loadDataTable;

        /// <span class="code-SummaryComment"><summary>

The client implementation of ICacheManager is even simpler, it holds a static dictionary of objects, the LoadDataTable method can point to the server's gateway delegate or can be left alone if you download only static tables to client side.

public class ClientCache : ICacheManager
    private static ClientCache clientCacheManager;
    private static Dictionary<string,> cacheMap;
    private ClientCache()
        cacheMap = new Dictionary<string,>();
    public static ClientCache GetClientCache()
        if (clientCacheManager == null)
            clientCacheManager = new ClientCache();
        return clientCacheManager;
    public object Get(string key)
        object result;
        cacheMap.TryGetValue(key, out result);
        return result;
    /// <span class="code-SummaryComment"><summary>

To allow the cache to be configured except the interval we sample the cacheItemQueue we use a simple XML that contains the list of tables to be cached.
Every element in this XML contains three attributes (except the name of the table of course):

  1. loadOnStart: load on application load or on first call.
  2. loadToClient: include table in the response to client's "getCache" method on client's load.
  3. refreshOnUpdate: if a cache table can be updated, this will be true (to be sure all tables that "refreshOnUpdate" have a trigger, we have a deployment utility that uses this same XML to automatically create these triggers and we check this matches on application load).

If I summarize the main idea:

  1. On application load, the cache data is retrieved to application server's memory, the server registers itself to receive updates & starts the thread checking for updates.
  2. Each dynamic table in cache has a trigger that is used to eventually notify the application server about the update and force it to refresh, the refresh could be made to the whole table (usually small tables with small number of writes) or you can use a timestamp column to identify which rows were updated and selectively refresh the cache.
  3. Every client on load retrieves a snapshot of the static cached tables to save roundtrips to server.

That's it for now, till next time...



This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Diego Resnik
Architect Ness Technologies
Israel Israel

You may also be interested in...

Comments and Discussions

GeneralMy vote of 5 Pin
Raj Champaneriya25-Nov-12 20:15
memberRaj Champaneriya25-Nov-12 20:15 
GeneralNCache, Distributed Caching,, Pin
wesnur23-Apr-10 1:26
memberwesnur23-Apr-10 1:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.170308.1 | Last Updated 22 May 2009
Article Copyright 2009 by Diego Resnik
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid