Monthly Archives: July 2012

Quickstart memcached

We have a legacy application of about ten years old, which uses a database for caching. Each time a request came in, the database was queried to look for that request with the specific input parameters, and if found, the cached version of the data was taken. This worked fine, except when there was a lot of traffic, where it became a bottleneck.

To remove this bottleneck, we needed another way of caching; and so we decided to replace it with memcached. This article describes my first test with setting up and using memcached to see how it works.

Referring to the definition “Free & open source, high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.”, we can say that memcached is like a short-term memory for your data. You can store simple and more complex objects in it, which makes your web site respond a lot faster than when it would have to get that data from a database each time. You can specify the amount of memory it can use – which means that if the memory is full, older data gets purged in a least recently used order.

It’s important to understand that servers are disconnected from each other, which means that if you have more than one server, each server is unaware of the others, so they are not synchronized. As such, the effect of adding more servers is that you will simply get more capacity. This means the client must have the intelligence to decide what server to use (Hashing/Key Distribution), as each of your data will be stored only once on exactly one of the memcached servers.

Memcached server

First we need to install memcached on the server. On the project site there are no packages, only sources; but you can download a windows package from here. I took the memcached 1.4.5 win64.zip version, which contains 2 files after you unzip it:

mc1

So copy these files somewhere on the server. In my case I used my development computer itself as the server.

Now you have to options: run it as a console application or as a service. Running it as a console application is fine if you are doing R&D, but for real development you should install it as a service of course.

It seems that the latest version cannot be run as a service anymore, it should be wrapped in something else to make it run as a service. Anyway, for my test, I’m just going to run it by starting the memcached executable with some parameters. So run the elevated command prompt (run as administrator), go to the location where you copied memcached and start it as follows:

memcached -p 12345 -m 64 –vv [ENTER]

where

  • p 12345 specifies the portnumber the memcached instance will listen to
  • m 64 specifies the amount of RAM in Mb that memcached will use for storage
  • vv controls verbosity (the amount of information that is logged)

The result will be a running memcached instance:

mc2

To test this, open a new command prompt, and type:

telnet 127.0.0.1 12345 [ENTER]

You will see an empty prompt:

mc3

Now type:

set mymessage 1 0 11 [ENTER]
Hello world [ENTER]

With this command, we have added a new key mymessage, with 1 as flag (arbitrary metadata), with 0 as the expiry (never expires), and with value which is 11 bytes long. If it succeeds, STORED will be displayed:

mc4

To get it back, type:

get mymessage [ENTER]

And you will get back the value again:

mc5

This proves that the memcached instance is running and working properly.

Memcached client

In order to make use of memcached server, we need a .NET client API that allows us to easily access the memcached server’s functionality. It seems that the enyim client is one of the most popular ones with a rich feature set, so I decided to go with this one. Just go to the downloads section, get the latest one (at this time that’s Enyim.Caching.2.9.zip) and unzip it. You should have this:

mc6

Copy this to your references or libraries folder, and from your visual studio project add a reference to Enyim.Caching.dll:

mc7

The next thing to do is to add a global MemcacheClient instance to you application. From the documentation:

Important! MemcachedClient is a “heavy object”, as in creating and initializing the client is quite expensive. (It has a socket pool inside, needs to calculate the tables for the consistent hashing, etc.) So, DO NOT create a client every time you want to perform an operation (well, you can, but 1) you need to Dispose() it after you finished, and 2) this will slow down your application considerably” 

So best practice is to initialize the instance only once, for example in a web application you would typically do this in the Application_Start method of global.asax; but we’re using a simple console application, so:

using Enyim.Caching;
using Enyim.Caching.Memcached;

namespace ConsoleApplication6
{
class Program
{
static void Main(string[] args)
{
using (var client = new MemcachedClient())
{
// Store message
client.Store(StoreMode.Set, "mymessage", "Hello world");

// Get message back from cache
var message = client.Get<string>("mymessage");
}
}
}
}

Before we can use the client, we have to configure it, so extend your application’s config file with:

<?xml version="1.0"?>
<configuration>

<configSections>
<sectionGroup name="enyim.com">
<section name="memcached"
type="Enyim.Caching.Configuration.MemcachedClientSection,
Enyim.Caching"
/>
</sectionGroup>
</configSections>

<enyim.com>
<memcached protocol="Binary">
<servers>
<add address="127.0.0.1" port="12345"/>
</servers>
</memcached>
</enyim.com>

</configuration>

If you build the application, you may get two build errors:

mc8

When you have this, it means probably that the target framework of your project is wrong. To fix it, right click your project and select properties; and make sure .NET Framework 4 is selected:

mc9

Build again, debug it and check whether message contains the correct value:

mc10

This proved that memcached is quite easy to setup.

What about the key?

In the previous example the key was short and simple. But in reality it could happen that keys are big – too big. Memcached allows keys of a maximum size of 250 characters (for a reason). In the case your keys are too big, you are probably better of generating a hash (which is unique) and use that hash as the key. Here’s some code that does that for you:

/// <summary>
/// Calculte the SHA1 hash of the given text.
/// </summary>
/// <param name="text">The text to calculate the hash for.</param>
/// <returns>Hash of specified text.</returns>
private static string HashString(string text)
{
string hash;
using (var sha1 = new SHA1CryptoServiceProvider())
{
var encoder = new UTF8Encoding();
hash = Convert.ToBase64String(sha1.ComputeHash(encoder.GetBytes(text)));
}
return hash;
}
Advertisements

Strategy pattern

Imagine the following scenario: we have some customer data that needs to be exported to an xml file somewhere. A solution could look like this:

public class Customer
{
    public Customer(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public void Export()
{
    // retrieve the data
    var customers = new List<Customer>();
    customers.Add(new Customer("Walter", "Jones"));
    customers.Add(new Customer("Timothy", "Dawson"));
    customers.Add(new Customer("Michael", "Boyce"));

    // Convert data to xml
    var xml = new XElement("customers",
        from c in customers
        select new XElement("customer",
            new XElement("firstName", c.FirstName),
            new XElement("lastName", c.LastName)
        ));
    var encodedDoc8 = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), xml);      

    // Create xml file
   encodedDoc8.Save(@"D:\temp\customers.xml");            
}

Nothing wrong with this approach, and the generated xml file looks fine:

But now let’s imagine that the generated xml should instead be exported to an ftp server, or the data should be formatted as a comma separated file, or maybe sent to an external service that processes it further. We would need to rewrite this method, or duplicate functionality, to support this. We don’t have the flexibility to easily replace or reuse functionality with this procedural approach.

Now the strategy pattern comes to the rescue!

First, we consider the export scenario to be a strategy. The export strategy consists of three steps:

  • Retrieve the data
  • Format the data
  • Publish the data in the new format

Each step of the strategy is a separate responsibility, which means that we are going to define an interface for each responsibility:

And for each interface, we will (at this time) have only one real implementation:

The MockRetriever implementation will generate some mock data, but later another retriever can be added that reads the data from a database.

The XmlFormatter implementation will take the data and formats it as XML, and later another publisher can be added that formats the data to a comma-separated format.

The FilePublisher implementation will take the formatted data and publish it as a file to some location on a hard drive, and later another publisher can be added that publishes the data somewhere on an FTP server.

So, in code, first add the interfaces:

public interface IRetriever
{
    IList<Customer> Retrieve();
}

public interface IFormatter
{
    MemoryStream Format(IList<Customer> customers);
}

public interface IPublisher
{
    void Publish(MemoryStream data);
}

And then the real implementations:

public class MockRetriever : IRetriever
{
    public IList<Customer> Retrieve()
    {
        var customers = new List<Customer>();
        customers.Add(new Customer("Walter", "Jones"));
        customers.Add(new Customer("Timothy", "Dawson"));
        customers.Add(new Customer("Michael", "Boyce"));
        return customers;
    }
}

public class XmlFormatter : IFormatter
{
    public MemoryStream Format(IList<Customer> customers)
    {
        // Convert data to xml
        var xml = new XElement("customers",
            from c in customers
            select new XElement("customer",
                new XElement("firstName", c.FirstName),
                new XElement("lastName", c.LastName)
            ));
        var encodedDoc8 = new XDocument(
                  new XDeclaration("1.0", "utf-8", "yes"), xml);
        var memoryStream = new MemoryStream();
        var xmlWriterSettings = new XmlWriterSettings 
                  { OmitXmlDeclaration = false, Indent = true };
        using (var xw = XmlWriter.Create(memoryStream, xmlWriterSettings)) 
                  { encodedDoc8.WriteTo(xw); }
        return memoryStream;
    }
}

public class FilePublisher : IPublisher
{
    public void Publish(MemoryStream data)
    {
        var fileToCreate = @"D:\temp\customers.xml";
        using (var outStream = File.OpenWrite(fileToCreate))
        {
            data.WriteTo(outStream);
        }
    }
}

Note that the formatter returns a memorystream, and the publisher takes a memorystream; to make them generic.

And now we can write the interface and implementation of the export strategy itself:

public interface IExportStrategy
{
    void Start();
}

public class ExportStrategy : IExportStrategy
{
    private IRetriever _retriever;
    private IFormatter _formatter;
    private IPublisher _publisher;

    public ExportStrategy(IRetriever retriever, 
            IFormatter formatter, IPublisher publisher)
    {
       _retriever = retriever;
       _formatter = formatter;
       _publisher = publisher;
    }

    public void Start()
    {
       var customers = _retriever.Retrieve();
       var formattedData = _formatter.Format(customers);
       _publisher.Publish(formattedData);
    }
}

Starting the export strategy is now easy and flexible: just register all real implementations with your favorite dependency injection framework, and then call the Start method of the export strategy. Using  another retriever, formatter or publisher is very easy to do: just register the ones you want to be used. Responsabilities are very clear, and you can easily test and mock each part of the strategy.

Another example

Suppose you have some cleanup mechanism, that needs a setting that comes from the configuration file (or a default one if it was not found in the configuration file):

public class Prices
{
public void CleanupPrices()
{
// Get number of days
var numberOfDaysConfig = ConfigurationManager.AppSettings["NumberOfDays"];
int numberOfDays;
if ((numberOfDaysConfig == null)
|| (!Int32.TryParse(numberOfDaysConfig, out numberOfDays)))
{
// some default value
numberOfDays = 7;
}

// Start cleanup here
}
}
 
To maximize reuse and flexibility, we could change this into a resolver:
 
public interface INumberOfDaysResolver
{
int Resolve();
}

public class NumberOfDaysResolver : INumberOfDaysResolver
{
public int Resolve()
{
// Get number of days
var numberOfDaysConfig = ConfigurationManager.AppSettings["NumberOfDays"];
int numberOfDays;
if ((numberOfDaysConfig == null)
|| (!Int32.TryParse(numberOfDaysConfig, out numberOfDays)))
{
// some default value
numberOfDays = 7;
}
return numberOfDays;
}
}

Then you can have it injected as follows:

public class Prices
{
private readonly INumberOfDaysResolver _numberOfDaysResolver;

public Prices(INumberOfDaysResolver numberOfDaysResolver)
{
_numberOfDaysResolver = numberOfDaysResolver;
}

public void CleanupPrices()
{
// Get number of days
var numberOfDaysConfig = _numberOfDaysResolver.Resolve();

// Start cleanup here
}
}