Scratching an itch: NMemcached

Last night I found myself up at 1 AM, feeling restless. I decided that I need a new project, something that is very simple and will allow me to channel some energy. I decided to pursue something that I have long been curious about, build a Memcached server in .Net. The Memcached server is a distributed cache server that is very popular in the Ruby, PHP & Perl worlds, with some following on both Java & .Net side.

It is written in C, and it is has some fairly interesting characteristics. Chief among them, it is a straightforward technical challenge. I spend about a day on this, but I have a working Memcached server, which can work with the existing clients.

Currently I support all the standard commands:

  • add
  • append
  • cas
  • delete
  • prepend
  • replace
  • set
  • get
  • gets
  • incr
  • decr
  • flush_all
  • quit
  • version

The only thing that I do not support is the stats command. The project has over a hundred unit tests and 34 integration tests and currently stand at 94% test coverage.

All of that said, what will probably interest most people is the performance comparison. I do hope that some people will stop to actually look at the design of the code, but here are the numbers, for reading / writing of 10,000 (small) values (over 10 iterations, using 20 connections):

Native Memcached finish in: 1709.6 ms

NMemcached completes in: 5768.5 ms

Update:

Based on profiling, I decided to make a tiny change to the part of the application that handles reading the commands from the user. Now it is reading them in continuous fashion, instead of one byte at a time. This brought the speed of the NMemcached version to 3144.5 ms, which is a huge benefit for such a small change.

Which put a project that was written in a day at just over 3 times slower than a heavily optimized piece of mature C code. Not bad, if I say so myself. I took a look with dot Trace, to see what was taking most of the time, and it looks like a significant amount goes in the networking section (specifically the LineReader class). There are a lot of tests, so it is not a problem to go and fix this if someone wants to.

You can access the code here: https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/experiments/NMemcached

Print | posted on Friday, June 06, 2008 6:28 PM

Feedback


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 7:08 PM cristian

Good work, checking out the code, btw, why not CacheMan (http://www.sriramkrishnan.com/blog/2008/02/cacheman-fast-distributed-hashtable-for.html) where you bored enough?


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 7:41 PM Sriram Krishnan

Interesating - I need to benchmark this against Cacheman on my machine . On my 2.4Ghz dual core dev box with 1gb RAM, I get around 16K read/writes per second.


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 8:02 PM Ayende Rahien

Cristian,
A/ yes.
B/ code is not available


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 8:38 PM Vijay Santhanam

Looks like fun. I'll check this out this weekend.

Why not use MS' Velocity?


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 9:08 PM Leverett

This is very clean. I like its simplicity. It essentially wraps System.Web.Caching.


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 9:12 PM Marco

If you're still bored, sometime ago you had some posts about a enterprise system, see http://ayende.com/Blog/archive/2007/11/17/A-vision-of-enterprise-platform.aspx

I love to see what you ideas are about an extensible UI like you describe in that blog post:

Extensible in an easy manner - note that this holds for business analysts and for developers, both are groups that are likely to do work on the system. Ideally we can have some sort of a common interface that would make both people happy.

* New entities
* User Interface:
o Forms
o UI elements
o Editing existing forms
* Replacing core services


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 9:29 PM Ryan Heath

You beat me up and down! :)

Great job!

I am implementing a memcache in C# in my sparse sparetime too.
But I didnt know I could use HttpCache in a service too, oh boy, that alone would have spared me a lot of hours of work.

Perhaps you should take a look at the .net 3.5 socket API which have greater performance compare to the IAsync pattern. And there are also a few SocketOptions which you could set, to get even more performance on the network stack.

// Ryan


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 10:09 PM Ayende Rahien

Marco,
That takes about a week, and compose a fairly complex architecture.


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 10:11 PM Ayende Rahien

Sriram,
What is the benchmark that you are running?
I am running a load test, basically open connections and try to happen the server using overlapped IO for getting things out of the client ASAP.
That said, I am assuming that your network code is significant more mature than mine. I paid no attention to perf during this stage


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 10:13 PM Ayende Rahien

Ryan,
Can you give me a url for that, I would love to see this.
Even better, a patch :-)


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 10:38 PM pete w

Lately I've been working less with .NET and I've picked up a project with ruby.

We are working with GemStone which doesnt rely on a traditional relational database, its more like a distributed cache of objects. You have objects on the disk, objects in distributed cache, and objects in worker processes and gemstone handles all of the concurrency.

The big difference is that there is no object mapping/transformations between the disk/cache/memory, they all have the same structure, it is simple byte copies, which makes it screaming fast.

Its written in smalltalk and I would love to interface that in .NET sometime.

This is a decent overview of gemstone:
http://www.avibryant.com/2008/03/index.html


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 11:35 PM Rob

Ayende...you're a sick, sick man...


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 11:57 PM Robert

Hi Ayende did you have a look at
http://www.codeplex.com/SharedCache/Release/ProjectReleases.aspx?ReleaseId=10755

From my perspective it looks promising.


Gravatar

# re: Scratching an itch: NMemcached 6/6/2008 11:57 PM Robert

Hi Ayende did you have a look at
http://www.codeplex.com/SharedCache/Release/ProjectReleases.aspx?ReleaseId=10755

From my perspective it looks promising.


Gravatar

# re: Scratching an itch: NMemcached 6/7/2008 2:58 AM Daniel

Hi Ayende,

I would second Macro. One week for a powerful and extensible enterprise framework would be a good investment, that will benefit a lot of people. Even a small profiling project would serve.


Gravatar

# re: Scratching an itch: NMemcached 6/7/2008 8:52 AM Jeffrey McManus

This is spectacular. Thanks for doing it. I know that the native win32 version of memcached has been without a maintainer for some time (a few years, actually, I think) and I'd theorized that if someone did a .NET port it might attract more contributors.

To answer a few people's questions about why use this instead of Velocity or CacheMan -- memcache has been around for years and there is already a large body of knowledge about how to use it to scale up a large dynamic site. There are also memcache client libraries written in .NET (and lots of other languages) already so the support is already there.

It's also worth mentioning that memcache is cross platform so if your application knows how to use memcache it can store cache data on any machine running any OS in your data center, as long as that machine has spare RAM. This is something that Velocity will not likely ever provide.


Gravatar

# re: Scratching an itch: NMemcached 6/7/2008 12:40 PM Ryan Heath

Look at http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx

MSDN has some examples too how to use it, and there are a lot of examples availble on the net.

// Ryan


Gravatar

# re: Scratching an itch: NMemcached 6/7/2008 1:20 PM Ayende Rahien

Nice, really nice. I'll have to try that


Gravatar

# re: Scratching an itch: NMemcached 6/7/2008 4:58 PM Steve

Next time you get restless, setup a asp.net mvc preview 3 project that uses just Boo for controllers, views, etc... uses NHibernate and DI (with Boo and no configuration files)

:)

After that I promise I will switch to boo :)


Gravatar

# re: Scratching an itch: NMemcached 6/8/2008 1:53 AM Federico

Hi Ayende,
Can you tell me which version of mbUnit are you using? BTW thanks for sharing, it's a nice way to learn.


Gravatar

# re: Scratching an itch: NMemcached 6/8/2008 2:54 AM Ayende Rahien

MbUnit 2.4


Gravatar

# re: Scratching an itch: NMemcached 6/8/2008 6:50 AM Mark Hildreth

You know, when you said...

"It is written in C,", for a minute I thought you were talking about your NMemcached project, not the original Memcached :P


Gravatar

# re: Scratching an itch: NMemcached 6/8/2008 8:27 AM gOODiDEA

hi Ayende,
can you test it for long time? I think GC will "destroy" cache although you set "System.Web.Caching.Cache.NoSlidingExpiration"


Gravatar

# re: Scratching an itch: NMemcached 6/8/2008 11:24 AM sirrocco

Actually it really shouldn't remove it if you set CacheItemPriority to High ... or if you want even - NotRemovable.

http://msdn.microsoft.com/en-us/library/system.web.caching.cacheitempriority.aspx


Gravatar

# re: Scratching an itch: NMemcached 6/8/2008 12:42 PM Ayende Rahien

gOODiDEA,
It won't. That is why it is on the cache.


Gravatar

# re: Scratching an itch: NMemcached 6/10/2008 6:38 AM Luke Q

At a glance it doesn't look like you allowed a cycle for the JIT to compile the code before the timing starts. The benchmarks that I've worked with allow time for results to converge, e.g. http://dacapobench.org/usage.html. This helps remove the JIT cost which is not really important for long running applications. Can you post some numbers with that approach?


Gravatar

# re: Scratching an itch: NMemcached 6/10/2008 11:37 AM Harry M

any chance you could write a cometd server next? :)


Gravatar

# re: Scratching an itch: NMemcached 6/10/2008 11:37 AM Ayende Rahien

This is running the client 10 times, using the exact approaches each time.
I include the first result, but it is not significantly higher than any other


Gravatar

# re: Scratching an itch: NMemcached 6/10/2008 11:59 AM Ayende Rahien

Harry,
Not likely, but a patch is always nice


Gravatar

# re: Scratching an itch: NMemcached 6/10/2008 1:22 PM Harry M

I'll get on it :)


Gravatar

# NMemcached 6/13/2008 5:03 PM Fahad

It's awesome to see a .net implementation of memcached. I think it would be great idea to add to the standard memcached protocol to include support for File Dependency and Sql Server dependency.


Gravatar

# re: Scratching an itch: NMemcached 6/13/2008 5:22 PM Ayende Rahien

Patches are welcome :-)


Gravatar

# re: Scratching an itch: NMemcached 6/17/2008 12:20 AM mycall

Q: Why did you call you class CacheMixin instead of making them extension methods? Your http://www.ayende.com/Blog/archive/2005/09/19/8285.aspx article isn't make this clear.

Thanks for the awesome project!


Gravatar

# re: Scratching an itch: NMemcached 6/17/2008 12:26 AM Ayende Rahien

I need to keep state, and extension methods do not provide this

Comments have been closed on this topic.