Should I use session or cache in this scenario? Or something else?

136 Views Asked by At

I have to create a mechanism to store and read preferences (controls default values and settings) per user. I have a problem related to network traffic, as the database can be accessed over the internet and the application server sometimes is connected to a poor 512Kbps internet connection.

My application can have around 50 simultaneous users and each page/form can have up to 50 items (preferences). The amount of pages is around 80.

So, considering a performance perspective, which should I choose to decrease network traffic? Session or cache?

UPDATE

I've created two sample pages, one using cache and another using session.

Load test 90 users

Stored content 1000 elements 20 characters on each element's value

Here are the results from each test case:

MemoryCache 330,725,246 total bytes allocated

Functions Allocating Most Memory

Name   Bytes %
System.Runtime.Caching.MemoryCache.Set(string,object,class System.Runtime.Caching.CacheItemPolicy,string)   34,74
System.Web.UI.Page.ProcessRequest(class System.Web.HttpContext) 18,39
System.String.Concat(string,string) 12,65
System.String.Join(string,string[]) 5,31
System.Collections.Generic.Dictionary`2.Add(!0,!1)  4,42

Source code:

protected void Page_Load(object sender, EventArgs e)
        {
            outputPanel.Text = String.Join(System.Environment.NewLine, ReadEverything().ToArray());
        }

        private IEnumerable<String> ReadEverything()
        {
            for (int i = 0; i < 1000; i++)
            {
                yield return ReadFromCache(i);
            }
        }

        private string ReadFromCache(int p)
        {
            String saida = String.Empty;
            ObjectCache cache = MemoryCache.Default;
            Dictionary<int, string> cachedItems = cache["user" + Session.SessionID] as Dictionary<int, string>;

            if (cachedItems == null)
            {
                cachedItems = new Dictionary<int, string>();
            }

            if (!cachedItems.TryGetValue(p, out saida))
            {
                saida = Util.RandomString(20);
                cachedItems.Add(p, saida);

                CacheItemPolicy policy = new CacheItemPolicy();
                policy.AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(30);
                cache.Set("user" + Session.SessionID, cachedItems, policy);
            }

            return saida;
        }

Session 111,625,747 total bytes allocated

Functions Allocating Most Memory

Name   Bytes %
System.Web.UI.Page.ProcessRequest(class System.Web.HttpContext) 55,19
System.String.Join(string,string[]) 15,93
System.Collections.Generic.Dictionary`2.Add(!0,!1)  6,00
System.Text.StringBuilder.Append(char)  5,93
System.Linq.Enumerable.ToArray(class System.Collections.Generic.IEnumerable`1) 4,46

Source code:

protected void Page_Load(object sender, EventArgs e)
        {
            outputPanel.Text = String.Join(System.Environment.NewLine, ReadEverything().ToArray());
        }

        private IEnumerable<String> ReadEverything()
        {
            for (int i = 0; i < 1000; i++)
            {
                yield return ReadFromSession(i);
            }
        }

        private string ReadFromSession(int p)
        {
            String saida = String.Empty;
            Dictionary<int, string> cachedItems = Session["cachedItems"] as Dictionary<int, string>;

            if (cachedItems == null)
            {
                cachedItems = new Dictionary<int, string>();
            }

            if (!cachedItems.TryGetValue(p, out saida))
            {
                saida = Util.RandomString(20);
                cachedItems.Add(p, saida);

                Session["cachedItems"] = cachedItems;
            }

            return saida;
        }

I forgot to mention that I'm creating a solution to work with ASP.Net and WPF projects, however, if the Session is far better than the MemoryCache option, I can have different solutions for each platform.

2

There are 2 best solutions below

0
On

both are really the same, they are in memory... If you are using DB session and you have a poor connection then you should use cache if present, load from DB if not and then cache.

2
On

I would consider the session a cache mechanism, unlike the others it is just specific to a specific browser session. My approach would consider the following questions.

  1. Is this site load balanced? If it is, using the session will force persistent sessions, possibly causing issues if you take down a server.

  2. Is this data user specific? If it is, the session is an easy way to segregate data without lots of key manipulation. It also has the benefit that when a user's session times-out it automatically gets cleaned up. If it isn't, I'd recommending using the MemoryCache feature added .NET 4.0. It supports expiration.

  3. How will this cache become outdated? If user A can modify data cached for user B, you're now serving dirty data with Session cache. This prompt a shared cache mechanism.

Edit: Once these questions have been answered, you should be able to decide what type of cache mechanism is appropriate for your situation. Then you can evaluate that subset for performance.