BLOG.PE-ELL.NET - Useless rambling...
BACK
:: 2010-01-28 20:01:59 ::

Quick and dirty benchmark...

So decided to do a quick benchmark since I'm still probing the "NoSQL" projects looking for potentially useful stuff.  Now these results didn't surprise me really since I'm been messing with these systems for a while.  But this is more for potential feedback and just so I don't forget.  Obviously the test is done in Perl and I force a connection for every loop (closest to our production).

For those that are unfamiliar:

Memcached:  Memory only key/value storage with ttl
MongoDB:    Memory/disk/replicated document storage with hash/array understanding (you can index anything) and completely binary safe, completely schema-less has built in filesystem
Redis:      Memory/disk/replicated key/value, list, set, ordered set storage with optional ttl (much lighter protocol than mongo)

MongoDB tends to try to offset things to the client in order to save server resources (sort, etc all happen client side).

CPU usage of server during run (via top):

    memcached    5-6%
    mongodb        4-7%
    redis              9-10%

[jstephens@ii52-27 (19:54:14) ~/test]$ perl test_redis_memcached.pl
                    Rate     mongo     redis     memcached
mongo           873/s         --         -3%      -16%
redis              901/s        3%        --         -14%
memcached 1044/s       20%       16%        --

Redis
    Server: 1.1.93-beta
    Client: Redis 0.0801

MongoDB
    Server: 1.1.4
    Client: MongoDB 0.26 (patched)

Memcached
    Server: 1.4.1
    Client: Cache::Memcached::Fast 0.14

Test script:

#!/usr/bin/perl

use strict;
use Cache::Memcached::Fast;
require 'Redis.pm';
use MongoDB;
use Benchmark qw/ cmpthese /;

cmpthese(10000, {
    memcached => sub {
            my $m = new Cache::Memcached::Fast { servers => [ 'xx.xxx.xxx.xx:11211' ], connect_timeout => 2, io_timeout => 1, max_failures => 3, failure_timeout => 2, };
            return "No memcached obj!" unless ref($m);

            my $p = gen_payload();
            $m->set( 'tkey', $p, 15 );
            my $v = $m->get('tkey');

            undef $m;
        },
    redis     => sub {
            my $r = Redis->new( server => 'xx.xxx.xxx.xx:6379' );
            return "No redis server!" unless $r->ping();

            my $p = gen_payload();
            $r->set( 'tkey' => $p );
            $r->expire( 'tkey', 15 );
            my $v = $r->get('tkey');

            $r->quit();
        },
    mongo     => sub {
            my $MONGO_CONN = MongoDB::Connection->new(host => "xx.xxx.xxx.xx");
            my $MONGO_DB   = $MONGO_CONN->get_database("common");
            my $MONGO_COLL = $MONGO_DB->get_collection("common");
            return "WE SUCK!" unless ref($MONGO_COLL);

            my $p = gen_payload();

            $MONGO_COLL->update({_id => 'tkey'}, { _id => 'tkey', txt => $p }, {"upsert" => 1});
            my $v = $MONGO_COLL->find_one({_id => 'tkey'});

            undef $MONGO_COLL;
            undef $MONGO_DB;
            undef $MONGO_CONN;
        },
    }
);



sub gen_payload {
    my $length = 2000;
    my $rand_length = 1;

    my @string;
    my @chars = ('a'..'f');
    my $possible_chars = scalar(@chars);
    push(@string, $chars[int(rand($possible_chars))]);

    my $end = $rand_length == 1 ? int(rand($length)) : $length;
    $end = 2 if $end <= 1;

    push @chars,(0..9,'/','+');
    $possible_chars = scalar(@chars);
    push(@string, $chars[int(rand($possible_chars))]) for(2..$end);

    return join('', @string);
}