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
Comments
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?
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.
Cristian,
A/ yes.
B/ code is not available
Looks like fun. I'll check this out this weekend.
Why not use MS' Velocity?
This is very clean. I like its simplicity. It essentially wraps System.Web.Caching.
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.
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
Marco,
That takes about a week, and compose a fairly complex architecture.
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
Ryan,
Can you give me a url for that, I would love to see this.
Even better, a patch :-)
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
Ayende...you're a sick, sick man...
Hi Ayende did you have a look at
http://www.codeplex.com/SharedCache/Release/ProjectReleases.aspx?ReleaseId=10755
From my perspective it looks promising.
Hi Ayende did you have a look at
http://www.codeplex.com/SharedCache/Release/ProjectReleases.aspx?ReleaseId=10755
From my perspective it looks promising.
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.
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.
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
Nice, really nice. I'll have to try that
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 :)
Hi Ayende,
Can you tell me which version of mbUnit are you using? BTW thanks for sharing, it's a nice way to learn.
MbUnit 2.4
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
hi Ayende,
can you test it for long time? I think GC will "destroy" cache although you set "System.Web.Caching.Cache.NoSlidingExpiration"
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
gOODiDEA,
It won't. That is why it is on the cache.
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?
any chance you could write a cometd server next? :)
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
Harry,
Not likely, but a patch is always nice
I'll get on it :)
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.
Patches are welcome :-)
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!
I need to keep state, and extension methods do not provide this
Comment preview