🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

In-Memory Key-Value Databases: NCache (Initial Evaluation)

posted in Septopus for project Unsettled World
Published October 31, 2018
C#
Advertisement

Okay, I'm not going to go into as much depth with this evaluation simply because I don't feel like I need to.

I'll provide the simple benchmark script(same as last one,just modified to use NCache instead) at the end.

NCache installed easy enough, but I had to update my powershell to use it(still hacking on Win7 for now) since I decided not to use their 60 day full GUI interface...

Overall it's very much similar to the setup/install experience of Redis, only the windows version of it, with the usual windows type quirks...;) 

The test environment is different though, NCache is running as a local service on my development machine, meaning it has full access to all 24G ram and 8 cores on my machine where-as Redis was running in a Linux VM on my machine with only 1 core and 4G of ram...

Now on to the results, initial test, 1Million writes/reads in a standard foreach through the dataset:

NCache_1M_standardforeach.png.4b4406ef4f3731205c7942c1bc24550d.png

Just slightly better than Redis..

And then the Parallel.ForEach test:

NCache_1M_parallelforeach.png.e9ac6511e31f7e3ce922e7344155f8c3.png

...Slower...hmm

And then I tried the NCache InsertAsync method inside a Parallel.ForEach method(this one Redis finished writing in under 10 seconds):

NCache_1M-2M_asyncparallelforeach.png.433d0cbddf69d1c9d7e7b6c585192e75.png

Granted, there were 1million records in the db when I started that test.

So, I cleared them out and ran the test again, 88 seconds for write time, and 107 seconds for read/verify...

Memory Usage!!  Redis I think topped out somewhere in the 500mb range, with multiple millions of records in the db.  NCache has been using between 1.5G and 2G+ consistently with only 1M records in the db & over 2.5G with 2million.  So, I ran a total of 4 tests against NCache and cleared the db 2 times, by the end of my testing the NCache service is sitting on 3.2G of memory, with 1million records in the  db.

I'm not going to get too into the configuration either, I'm sure there are options that could be tuned and whatnot.. 

I love simplicity, I love out of the box performance, I love friendly and efficient use of memory, and so far Redis is pretty far ahead in all 3 categories.

So, what's next?  Well, I need to do just a little more research and configuration testing on Redis to make sure it will hold up the way I would need it to, then I start coding again..  I may look into a distributed messaging solution like ZeroMQ as a possible augment, or alternative to the KV db as well.  Still got some gears to turn here and there.

Test Script:


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Alachisoft.NCache.Web.Caching;

namespace TestCache
{
    class Program
    {
        static Dictionary<string, string> TestDataSet = new Dictionary<string, string>();
        //static ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("192.168.56.101");
        static Stopwatch sw = new Stopwatch();

        static void Main(string[] args)
        {
            //Build Test Dataset
            Console.Write("Building Test Data Set.");
            int cnt = 0;
            for (int i = 0; i < 1000000; i++)
            {
                cnt++;
                TestDataSet.Add(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());
                if (cnt > 999)
                {
                    cnt = 0;
                    Console.Write(i.ToString() + "_");
                }
            }
            Console.WriteLine("Done");

            string cacheID = "uwNCacheTest";
            Cache csh = NCache.InitializeCache(cacheID);
            sw.Start();
            //Console.WriteLine("Starting 'write' Benchmark");
            //foreach (KeyValuePair<string, string> kv in TestDataSet)
            // {
            //   csh.Insert(kv.Key, kv.Value);
            //}
            Console.WriteLine("Starting Async Parallel 'write' Benchmark.");
            Parallel.ForEach(TestDataSet, td =>
            {
                //db.StringSet(td.Key, td.Value);
                //    db.StringSetAsync(td.Key, td.Value, flags: CommandFlags.FireAndForget);
                //csh.Insert(td.Key, td.Value);
                csh.InsertAsync(td.Key, new CacheItem(td.Value), DSWriteOption.None, null);
            });
            Console.WriteLine("TIME: " + (sw.ElapsedMilliseconds / 1000).ToString());
            sw.Restart();
            //Console.WriteLine("Testing Read Verify.");
            //foreach (KeyValuePair<string, string> kv in TestDataSet)
            //{
            //    if (csh.Get(kv.Key) as string != kv.Value)
            //    {
            //        Console.WriteLine("Error Getting Value for Key: " + kv.Key);
            //    }
            //}
            Console.WriteLine("Testing Parallel Read Verify");
            Parallel.ForEach(TestDataSet, td =>
            {
                //if (db.StringGet(td.Key) != td.Value)
                if (csh.Get(td.Key) as string != td.Value)
                {
                    Console.WriteLine("Error Getting Value for Key: " + td.Key);
                }
            });
            Console.WriteLine("TIME: " + (sw.ElapsedMilliseconds / 1000).ToString());
            sw.Stop();
            Console.WriteLine("Press any key..");
            Console.ReadKey();
        }
    }
}

 

1 likes 0 comments

Comments

Rutin

Interesting. Thanks for sharing. :) 

October 31, 2018 03:52 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement