Trond Norbye's Weblog

« Trondheim OpenSolari... | Main | noreply support in... »

http://blogs.sun.com/trond/date/20090120 Tuesday January 20, 2009

noreply support in libmemcached

The memcached textual protocol allows you to execute commands on the memcached server without sending the result back to you. Why would you want to do this? One case could be that you just want to store the item in the cache, and you don't really care if it is successful or not. Up until today you had two modes you could use to insert items in the cache: synchronous (default) and asynchronous.

If we look at the following code snippet:

  for (int x= 0; x < 100; ++x) {
    char key[10];
    size_t len= sprintf(key, "%d", x);
    if (memcached_set(memc, key, len, key, len, 0, 0) != MEMCACHED_SUCCESS)
      abort();
  }
  memcached_quit(memc);

During the execution of the above loop, libmemcached will send the set command to the server and wait for the response from the server before it sends the next command to the server etc. This is not very efficient, so you may use the asynchronous mode to queue up commands. To do that, we modify the code:

  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
  for (int x= 0; x < 100; ++x) {
    char key[10];
    size_t len= sprintf(key, "%d", x);
    memcached_response ret;
    ret= memcached_set(memc, key, len, key, len, 0, 0);
    if (ret != MEMCACHED_SUCCESS && ret != MEMCACHED_BUFFERED)
      abort();
  }
  memcached_quit(memc);

With this modification, libmemcached will buffer multiple requests to the server and send them to the server when the buffer exceeds a configurable threshold.

Now this sounds pretty neat doesn't it? Well it is one problem with the model, and that is if we try to issue a get command. The problem now is that we need to flush the send buffer and let the server execute all of the commands in the send buffer before we can send the get request. If we are lucky the buffer is empty (or just contain a few commands), but it could potentially contain a lot of set commands and the memcached server could use some time processing all of those commands.

To solve this problem I implemented use of the noreply command (If you are interested in the glory details, take a look at the patch). So let me modify the source code once more:

  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 1);
  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NOREPLY, 1);
  for (int x= 0; x < 100; ++x) {
    char key[10];
    size_t len= sprintf(key, "%d", x);
    memcached_response ret;
    ret= memcached_set(memc, key, len, key, len, 0, 0);
    if (ret != MEMCACHED_SUCCESS && ret != MEMCACHED_BUFFERED)
      abort();
  }
  memcached_quit(memc);

With this modification libmemcached will send the command to the memcached server immediately, but it also tells the server that it doesn't want a reply from the server so it doesn't wait for a response before it sends the next command. When I implemented this patch I noticed that the binary protocol didn't have support for all of the "noreply" variants of the commands, so I filed a bug report on memcached (and implemented it as well ;-)).

Comments:

Hi!

Even with no-reply we should buffer up multipe SET operations (or come up with a bulk set for callback). The reason is that half the gain is in not sending as many patches.

Cheers,
-Brian

Posted by Brian Aker on January 21, 2009 at 01:24 AM CET #

Post a Comment:
  • HTML Syntax: NOT allowed

Valid HTML! Valid CSS!

This is a personal weblog, I do not speak for my employer.