KVS最速テスト第二弾(memcached V.S. Redis)

前回のテストで,とりあえずキャッシュとしての速度だけ考えるとmemchachedがやはり最速だということが分かったので,今回はmemcachedと話題のRedisを比較しました.Redisは非同期でディスクに書き出されるのが特徴ですが,memcachedはともかく,memcached-haはレプリケーションで他サーバに飛ばせるので,それほど負けてもいません.

RedisもKyoto Tycoonと同様,memcachedプロトコルじゃないので,ソケット通信をPocoで実装しました.

#include <sstream>
#include <iostream>
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/Net/StreamSocket.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include "Poco/StreamCopier.h"

using namespace std;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <md5.h>
#include <omp.h>

void set_key_val(MD5_CTX *con, int seed, char *key, char *val)
{
  sprintf(key,"stress-test-%010d",seed);
  sprintf(val,"%010d",seed);
  MD5Init(con);
  MD5Update(con, key, strlen(key));
  MD5End(con, key);
}
#define MAX 1000000
#define BUFFER_SIZE 256
int main(int argc, char *argv[])
{
  int suc = 0, i;
  time_t start, set_end, get_end;
  int n = omp_get_max_threads();
  vector<Poco::Net::StreamSocket *> pool(n);
  Poco::Net::SocketAddress server(argv[1], 11211);
  for(vector<Poco::Net::StreamSocket *>::iterator i=pool.begin(); i!=pool.end();++i)
  {
    *i = new Poco::Net::StreamSocket(server); // スレッド数だけコネクションプールを作る
  }
  start = time(NULL);
#pragma omp parallel for shared(suc,i)
  for(i=0;i<MAX;++i)
  {
    Poco::Net::StreamSocket *client=pool.at((int)(i/(MAX/n)));
    MD5_CTX con;
    char key[33], val[11];
    set_key_val(&con, i, key, val);
    char write_buffer[BUFFER_SIZE], read_buffer[BUFFER_SIZE];
    int sent_len, recv_len;
    snprintf(write_buffer, BUFFER_SIZE,
            "*3\r\n$3\r\nSET\r\n$%d\r\n%s\r\n$%d\r\n%s\r\n",
              strlen(key), key, strlen(val), val);
    sent_len = client->sendBytes((void *)write_buffer, strlen(write_buffer));
    // sent contents
    //cout<<write_buffer<<endl;
    recv_len = client->receiveBytes(read_buffer, BUFFER_SIZE);
    // received contents
    //cout<<read_buffer<<endl;

    if (sent_len != strlen(write_buffer) || strncmp(read_buffer,"+OK\r\n", 5)!=0)
    {
      fprintf(stderr, "set: %s: redis error %s", key, read_buffer);
      fprintf(stderr, "\n");
    }else
    {
      ++suc;
    }
    client = NULL;
  }
  set_end = time(NULL);
#pragma omp parallel for
  for(i=0;i<MAX;++i)
  {
    Poco::Net::StreamSocket *client=pool.at((int)(i/(MAX/n)));
    MD5_CTX con;
    char key[33], val[11];
    set_key_val(&con, i, key, val);
    char write_buffer[BUFFER_SIZE], read_buffer[BUFFER_SIZE];
    char confirm_buffer[BUFFER_SIZE];
    int sent_len, recv_len;
    snprintf(write_buffer, BUFFER_SIZE, "*2\r\n$3\r\nGET\r\n$%d\r\n%s\r\n", strlen(key), key);
    sent_len = client->sendBytes((void *)write_buffer, strlen(write_buffer));
    // sent contents
    //cout<<write_buffer<<endl;
    recv_len = client->receiveBytes(read_buffer, BUFFER_SIZE);
    read_buffer[recv_len] = '\0';
    // received contents
    //cout<<read_buffer<<endl;
    snprintf(confirm_buffer, BUFFER_SIZE, "$%d\r\n%s\r\n", strlen(val), val);
    if (sent_len != strlen(write_buffer) ||
          strncmp(read_buffer, confirm_buffer, strlen(confirm_buffer))!=0)
    {
      fprintf(stderr, "get: %s: redis error %s", key, read_buffer);
      fprintf(stderr, "\n");
    }else
    {
      ++suc;
    }
  }
  get_end = time(NULL);
  printf("try=%d success=%d ratio=%f\n",MAX,suc/2,(double)suc/2/MAX*100.0);
  printf("set=%d[sec], get=%d[sec], total=%d[sec]\n",
           set_end-start, get_end-set_end, get_end-start);
  return(0);
}

memcachedは前回と同じくlibmemcachedを使ったもので.
memcachedもredisも速いと予想されるので,Key-Valueの数(=ループ回数)も10倍にして検証精度を高めました.すなわち,ループ回数MAX=100万回に.
ただ,そうするとmemcachedの方がデフォルトの記憶容量64Mbyteを超えて最初の方にsetした値が消えてしまったので,確保容量を拡張するように立ち上げました.

 ./memcached-ha -p 11211 -m 256

Redisはデフォルト1Gっぽいです.

 server.vm_max_memory = 1024LL*1024*1024*1; /* 1 GB of RAM */

今回もOpenMPを使ってスレッド数を変化させて同時並行アクセス数を変えてテストしました.
とりあえず,やはりmemcached-haが最速でした.

まずset結果.

次にget結果.

最後にsetとgetのタイムを合わせたトータルの結果.

速度だけ見ると,memcachedの圧勝です.
ただし,memcahcedがひたすらシンプルなのに対し,RedisやKyoto Tycoonは性能が良いのは確かです.
どれにも言えることは,プロトコルが分かりやすいことです.SQL/RDBMSに比べると,格段に拡張性や利便性(ボトルネックの調査のしやすさなど)が優れています.

Calbee ポテトチップス パリパリバリエーション No.119 期間限定 グリルビーフR

甘辛ですね〜美味しい〜

原材料名は,「じゃがいも(遺伝子組換えでない)」「ビーフパウダー(豚・鶏を含む)」「粉末しょうゆ(小麦・大豆を含む)」「酵母エキスパウダー」「コーンスターチ」「食塩」「オニオンパウダー」「ベーコンシーズニング」「乳糖発酵トマトエキスパウダー」「ジンジャーパウダー」「西洋わさび」「洋からし」「甘味料(ステビア)」「くん液」等で,カロリーは70グラム当たり387kcal,ナトリウムの食塩相当量は1.1グラムだそうです.