Stress Test Script

Stephen Woodbridge woodbri at swoodbridge.com
Fri Jun 9 18:10:51 UTC 2006


Hi all,

I wrote a simple script to stress test memcached as part of an 
experiment to see how it behaved. I'm not sure how valid this test is 
but I am interested in knowing about some strange behavior we ran into.

The test is pretty simple and straight forward:

1) generate a key using an md5 hash of a counter, ie: 0,1,2,3,...
2) create data for the key using a random size between 1 and 20k bytes
3) do a "set" followed by a "get", if the data doesn't compare, log it 
as an error
4) print on a stats report of "count, failed, MB's set"
5) loop forever

We then fired off multiple scripts and hammer the server.

The good news is that running 1-5 scripts seem to have a constant load 
of about 12-15% of the cpu an a 1GB cache. After pushing a large number 
of GB through the cache (like 64 GB+, don't remember the exact number) 
we started getting a lot for failures on the test clients, like one was 
failing 30% and another failing 60% of its sets. Restarting the server 
cleared the problem until we pushed a lot of data through the cache again.

So what is going on? Is this the cache fragmentation problem? Is there a 
fix for this problem? Other thoughts?

Thanks,
   -Steve

Here is the script if you want to try it, or comment on it.
./memcache-test server=localhost stress=0

#!/usr/bin/perl -w
use strict;

use Cache::Memcached;
use Data::Dumper;
use Digest::MD5 qw(md5_hex);
use CGI;

my $cgi = new CGI;
my $server  = $cgi->param('server');
my $service = $cgi->param('service') || '';
my $cid     = $cgi->param('cid');
my $data    = $cgi->param('data');
my $stress  = $cgi->param('stress');
my $size    = $cgi->param('size');

my $go      = 1;
my $cnt     = 0;
my $byte    = 0;
my $fail    = 0;

Usage() if ! ($server && ($cid || defined $stress));


sub catch_int {
     my $sig = shift;
     #warn "Caught SIG$sig\n";
     $go = 0;
}

sub report {
     printf("cnt=%7d, fail=%7d, data=%d MB\n", $cnt, $fail, $byte);
}

sub makekey {
     my $idx = shift;
     return md5_hex($idx);
}


sub setncheck {
     my $mc   = shift;
     my $key  = shift;
     my $size = shift;

     $size = int rand 20000 if ! $size;
     my $data = $key x ($size/length($key));
     $mc->set("$key.stress", $data);

     my $rdata = $mc->get("$key.stress");
     $fail++ if $data ne $rdata;
     $cnt++;
     $byte += length($rdata) / (1024*1024) if $rdata;
     report() if $cnt % 1000 == 0;
}

my @srv = split(/,/, $server);
my @srvb = ();
for my $x (@srv) {
     if ($x !~ m/:\d+$/) {
         $x =~ s/$/:11211/;
     }
     push @srvb, $x;
}
print "servers = " . join(', ', @srvb) . "\n";

my $mc = new Cache::Memcached {'servers' => \@srvb,
                             #   'debug' => 1,
                                };
if (! $mc) {
     print "ERROR: could not connect to Memcached on $server\n";
     exit(0);
}
else {
     if ($cid) {
         $mc->set("$cid.$service", $data)
             if $data && length($data);

         print "Response:\n";
         my $response = $mc->get("$cid.$service");
         print "key=$cid.$service\n";
         print Data::Dumper->Dump([$response], ['response']);
     }
     else {
         if ($stress > 0) {
             for my $x (1..$stress) {
                 setncheck($mc, makekey($x), $size);
             }
         }
         else {
             $SIG{INT} = \&catch_int;
             my $x = 1;
             while ($go) {
                 setncheck($mc, makekey($x), $size);
             }
             $SIG{INT} = 'DEFAULT';
         }
     }
     report();
}

exit(0);

sub Usage {
     die "Usage: memcache-test server=<host> service=<string> cid=<cid> 
data=<string>\n" .
         "  <host> is the IP or name of the memcached server (REQUIRED)\n" .
         "         it maybe a comma separated list of servers\n" .
         "  <stress> is the number of items to store in a stress test, 0 
= infinite\n" .
         "  <size> is the size of the item to store (OPTIONAL), default 
is random\n" .
         "    -------- or ---------\n" .
         "  <host> is the IP or name of the memcached server (REQUIRED)\n" .
         "         it maybe a comma separated list of servers\n" .
         "  <service> is the fcache service string (OPTIONAL)\n" .
         "  <cid> is the fcache ID to set or get (REQUIRED)\n" .
         "  <data> is a string that will be set for the <cid>.<service> 
(OPTIONAL)\n";
}


More information about the memcached mailing list