Firstly, what is Memcached and why would it be better than say using the inbuilt .net cache
If you are running a your .NET website from a single server there is very little point in even considering Memcached. Memcached is “Free & open source, high-performance, distributed memory object caching system” (http://memcached.org/). So if you are running your site from many web servers it may be preferable to have a shared cache. If you have performance draining database calls originating from your web servers you may want the first web server to make the database call to cache the result in the shared cache, so the other web servers don’t need to make the same database call.
How does it work
Memcached is a distributed memory object cache, so how does it actually distribute?
Effectively the Memcached server is simply a key value store so it is up to the client to pick the correct server to put the object on. The way it picks is to hash the key for the item you want to store and compute from that which server that item should be placed on. If you had two servers the split of items between the two should be approximately 50-50.
Choosing a client
There are two popular free clients to choose from BeIT and Enyim. I have quickly evaluated both and here are my findings:
BeIT
Setting up the client
Setting up the client in my app could not be easier. Firstly use that static Setup method on the MemcachedClient to set up the configuration for your Memcached client.
MemcachedClient.Setup("MyCache", new string[] { "127.0.0.1:11211" });
The first parameter is the Identifier for your Memcache client configuration and the string array is the the addresses of the memcached servers. In this example I am using the loopback address because I am running the server on my local box.
Once you have created this you can use the static GetInstance method on the MemcachedClient to retrive an MemcachedClient instance for this configuration.
MemcachedClient cache = MemcachedClient.GetInstance("MyCache");
Alternatively, and probably more useful, you can put the Client settings in a configuration section in the your application configuration file, you can then use then use the MemcachedClient.GetInstance() method to get an MemcachedClient instance for the configuration specified.
Using the client
Once you have set up the client you are free to change the settings and use the methods to interact with you Memcached server.
cache.Set("mystring", "helloMemcached", 4711); cache.SetCounter("users", 0); cache.Increment("users", 1);
Supported methods
- Set – store this data
- Add – store this data, but only if the server doesn’t already
hold data for this key - Cas – Check And Store, store this data but
only if no one else has updated since I last fetched it. - replace – store this data, but only if the server does
already hold data for this key - append – add this data to an existing key after existing data
- prepend – add this data to an existing key before existing data
- Get(s) – The the value associated with a particular key. Gets will retrieve many
- SetCounter – Set a counter that can then be incremented with Increment and Decrement methods
- Increment – Will increment the value by the specified amount
- Decrement – Will decrement the the value by the specified amount
- Delete – Deletes an item
- FlushAll – Deletes all items on all servers
- Exists – Check to see if an item exists
- Stats – Get key/value stats for each server
- StatsByHost – Get key/value stats for each server
Enyim
Setting up the client
Setting up the client is pretty easy in Enyim also. You can put the settings in the application configuration file saving you having to set up the configuration in code.
Enyim.Caching.Configuration.MemcachedClientConfiguration config = new Enyim.Caching.Configuration.MemcachedClientConfiguration(); config.Servers.Add(new System.Net.IPEndPoint(IPAddress.Loopback,11211)); config.Protocol = Enyim.Caching.Memcached.MemcachedProtocol.Text; //you must set a protocol Enyim.Caching.MemcachedClient client = new Enyim.Caching.MemcachedClient(config);
Using the client
client.Store(Enyim.Caching.Memcached.StoreMode.Add, "myItem", "myValue"); //The various ways of storing things use a single method and an enum rather than 3 methods client.Store(Enyim.Caching.Memcached.StoreMode.Replace, "myItem", "myValue"); client.Store(Enyim.Caching.Memcached.StoreMode.Set, "myItem", "myValue");
Supported methods
- Store – Stores the data specified under the specified key, takes an Enum that dictates if it is an Add/Replace/Set
- Cas – Check And Store, store this data but
only if no one else has updated since it was last fetched - Append – Add this data to an existing key after existing data
- Prepend – Add this data to an existing key before existing data
- Get – Gets the value associated with a particular key.
- Get<T> – Generic version of Get
- GetWithCas – Get the value associated with a particular key and will also return check and set value
- GetWithCas<T> – Get the value associated with a particular key and will also return check and set value
- TryGet - Tries to get an object from the cache, if it fails the output object is null
- TryGetWithCas - Tries to get an object from the cache, if it fails the output object is null
- PerformMultiGet – Gets many thing at once
- Increment – Will increment the value by the specified amount, you can specify a default if the key doesn’t already exist
- Decrement- Will decrement the the value by the specified amount, you can specify a default if the key doesn’t already exist
- Remove- Deletes an item
- FlushAll- Deletes all items on all servers
- Exists – Check to see if an item exists
- Stats – Get key/value stats for each server
- StatsByHost – Get key/value stats for each server
Feature comparison
| Enyim | BeIT | |
| Config file configuration | yes | yes |
| Persistent connections | yes | yes |
| Generic get and set methods | yes | no |
| Supports Binary protocol | yes | no |
| Supports SASL | yes | no |
| Supports all the standard Memcached operations in the protocol | yes | yes |
| Uses .NET serialization | yes | yes |
| Consistent hashing | yes | yes |
| Compression (built-in) | no | yes |
| Logging and tracing | yes | yes |
Conclusion
Both work well. Enyim doesn’t have compression, but there is nothing stopping you using the .NET framework compression features. I think overall Enyim does have a richer feature set. Anecdotally I have heard that Enyim is faster, but that is likely to be due in part to it not compressing the objects before it sends them to the server. The support for the Binary protocol doesn’t mean that much to me, yes it will mean that less bytes need to be pushed down the pipe for the commands but I don’t think it will make a significant difference because most of the bytes (to be sent) are likely to be the bytes of the serialized object you wish to store. Both use the standard .NET Binary formatter so you can use the ISerializable interface on your types if you are worried about the shape of the type changing while old objects are still in the cache.