# In-Memory Key-Value Databases: Redis (Initial Evaluation)

1323 views

This is the first of at least two posts regarding my evaluation of the addition of an In-Memory(RAM) Key-Value Database system to my server architecture.  If you're unfamiliar, check out https://en.wikipedia.org/wiki/Key-value_database, for some broad spectrum info.

I'm beginning with Redis, it runs on Linux which is my scale-up server platform of choice, and this database will be the key to the scalability of my server architecture.  It's also open-source and has been around for a while now.

Documentation: https://redis.io/documentation

Installation was pretty straight forward, I created a Centos7 VM using Oracle's VirtualBox software (https://www.virtualbox.org/ one of the easiest ways to use vms locally I've used on Windows),

It has been a couple years since I worked on a  Linux machine, but I still managed to figure it out:

So, that's a working installation.  Easy as 1,2,3..

Okay, a simple benchmark,VM is using a single core and 4G of ram, and I'm using the StackExchange.Redis client from NuGet:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using StackExchange.Redis;

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

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++;
if (cnt > 999)
{
cnt = 0;
Console.Write(i.ToString() + "_");
}
}
Console.WriteLine("Done");

IDatabase db = redis.GetDatabase();

Stopwatch sw = new Stopwatch();
sw.Start();
//Console.WriteLine("Starting 'write' Benchmark");
//foreach (KeyValuePair<string, string> kv in TestDataSet)
//{
//    db.StringSet(kv.Key, kv.Value);
//}
Console.WriteLine("Starting Parallel 'write' Benchmark.");
Parallel.ForEach(TestDataSet, td =>
{
db.StringSet(td.Key, td.Value);
});
Console.WriteLine("TIME: " + (sw.ElapsedMilliseconds / 1000).ToString());
sw.Restart();
//foreach (KeyValuePair<string, string> kv in TestDataSet)
//{
//    if (db.StringGet(kv.Key) != kv.Value)
//    {
//        Console.WriteLine("Error Getting Value for Key: " + kv.Key);
//    }
//}
Parallel.ForEach(TestDataSet, td =>
{
if (db.StringGet(td.Key) != 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..");
}
}
}

Basically I'm creating a 1million record Dictionary filled with Guids(keys & values). Then testing both a standard foreach and a parallel.foreach loop to write to Redis and then read from Redis/compare to dictionary value.

Result times are all in seconds.

Standard foreach loop(iterating through dictionary to insert into redis):

Almost 5minutes to write and another almost 5 minutes to verify..

Using the Parallel.Foreach method:

and then again with 1M records already present in DB:

And then with 2M records present in DB:

And then with 3M:

and 4M:

Well, you get the picture..

So far, I think I really like Redis.

And now with the async "fire and forget" set method (db write without response), on empty db:

Console.WriteLine("Starting Parallel 'write' Benchmark.");
Parallel.ForEach(TestDataSet, td =>
{
//db.StringSet(td.Key, td.Value);
db.StringSetAsync(td.Key, td.Value, flags: CommandFlags.FireAndForget);
});

Easy enough code change.

Well, that's pretty fancy.  1 Million records added in under 10 seconds, and not a single error..

So, even though I think this is my winning candidate, I should at least perform the same benchmarks on NCache to see if it somehow blows Redis out of the water.

So, keep posted, as NCache will be my next victim.  It may be somewhat unfair though since I'll be installing NCache on my Windows machine directly and Redis was sequestered into a tiny vm with very limited resources, so if I need to(if NCache is ridiculously faster ootb) I'll be re-running these benchmarks again on a bigger VM.

A few more benchmark results(11/1/18):

I've repeated the final "fire and forget" with a couple bigger data sets.  Same VM, so 1 single core, and 4G ram.

2 Million Records:

This shows the top output snapped somewhere in the middle of the "write" test.

This shows the benchmark output, the Redis cli console, and top for the Redis server.  Post benchmark.

Now 10Million Records:

Redis Server Top output somewhere in the middle of the "write" test.  We're hitting that single core ceiling here, but it's trucking along anyhow.

Here's a snap from somewhere in the middle of the read/verify test.  Working hard, but not taxing that single core.  Up to 2G of ram now, 10m records.. not too bad.

And the completed test.  Frankly, I'm impressed.  It pegged the single core for a fraction of that 83 seconds, but it didn't lose a single record in the process.

And the final test result: a 1million record write, with 10million records already in the DB.   Boom, still no errors.

So, let us really break it good.

I rewrote the benchmark script to Parallel.Foreach through 10 individual 1million record benchmark tests.  Roughly simulating separate concurrent clients to the Redis server.

And here is where we start finding limits in (this) installation/configuration.

So, it got to about 3Million records inserted from 6 different connections before the load on the server caused the additional connections to time out(more or less).

Okay, lets try it with 6 connections.  hmm, I have 6 servers.. hmm.

Mid write, good to go.

And would you look at that, no exceptions, no read errors.

## 1 Comment

A general observation of your use of Parallel.Foreach and StringSetAsync; the test you're performing there is actually one of how fast you are putting work onto the task scheduler - you're not awaiting the completion of the task (which itself could be problematic in the event of an exception).

5 hours ago, evolutional said:

A general observation of your use of Parallel.Foreach and StringSetAsync; the test you're performing there is actually one of how fast you are putting work onto the task scheduler - you're not awaiting the completion of the task (which itself could be problematic in the event of an exception).

Very true indeed.  Which was why it wasn't the only test.  Regardless, out of the box Redis didn't stumble.  I wasn't really going for a complete benchmark test here either.  More establishing a behavioral baseline which I could use to compare to other products.  I'll be finding its actual hard limits later, I'm sure.  That being said though, if I ever have 1000000 records that need to go into the database in under 10 seconds, I'll probably already have clusters of servers to split the load, so it will likely never be actually used like that in production anyhow.

Also important to note, I wasn't attempting to benchmark the abilities of Redis to handle errors.  I was benchmarking its ability to handle data WITHOUT errors.   I should have reiterated that test with multiple millions of records until it started to fail on retrieval.  That would give me the upper limit if Redis' capabilities.  And now that I think about it, I want to know that information.

Thanks!

Many more benchmark results added(to this blog article) today.

## Create an account

Register a new account

• ### Similar Content

using System.Collections; using System.Collections.Generic; using UnityEngine; public class BillboardFX : MonoBehaviour { public Transform camTransform; Quaternion originalRotation; void Start() { originalRotation = transform.rotation; } void Update() { transform.rotation = camTransform.rotation * originalRotation; } } S﻿cript Lin﻿k﻿: ﻿https://github.com/ThisIsFix/Unity-Billboard

• We are currently working in a new indie Survival Crafting game, the project "Putrid" is looking for focused resource farming and modifiable environment.
The project have an advanced state of development with many items and assets.
We want a programmer with experience in c# to handle the main mechanics of the game.

here's our Discord: https://discord.gg/hZQYapv
and here's my mail for any doubts: tyxefield@gmail.com

• Hello,
So I have been programming with C++ for 2.5 years now. I have been interested in checking out C# for fun. My question is pretty simple. Does C# use a form typically for their games? The simple game examples I have watched on YouTube reminds me A LOT of Visual Basic.
Was this just an easy way to show you C#? Or using the form is a big part of C#? Or is it nothing more than using something like MFC and completely irrelevant to making games?
Thanks

• Hi i´m currently working on  a SciFi-Shooter and im looking for people to help me.
If you´re interessted dm me here.
• By felix.d
Hello,
i am Felix from Tübingen. I want to develop animated movies and games. If anyone has the same plans and no partners, please whatsapp me +4917656922229.
I need people to exchange ideas with