libmemcachedのレプリケーション実験

今日は元々は,大量に実装されているlibmemcachedのハッシュについて書こうと思ったのですが,
Consistent Hashingを計算してみる - なぜか数学者にはワイン好きが多い

ドキュメントを見ていたら,こんなオプションがあるのに気付いてしまいました.

MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS

If you just want "a poor mans HA", you may specify the numbers of replicas libmemcached should store of each item (on different servers). This replication does not dedicate certain memcached servers to store the replicas in, but instead it will store the replicas together with all of the other objects (on the 'n' next servers specified in your server list).

klabさんでしたっけ,repcachedとか作ってはった方がおりましたが,メモリベースで良ければ,デフォルトでレプリケーションがあった!?
さっそく実験です.

普通のバージョン.
プログラムはこんな感じです.

#include <libmemcached/memcached.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
  memcached_st *memc;
  memcached_return rc;
  memcached_server_st *servers;
  char *key, *val;

  memc= memcached_create(NULL);

  servers= memcached_servers_parse(argv[1]); // サーバ群
  key = argv[2];
  val = argv[3];

  memcached_server_push(memc, servers);
  memcached_server_list_free(servers);

  rc= memcached_set(memc, key, strlen(key), val, strlen(val), 0, 0);

  if (rc != MEMCACHED_SUCCESS)
  {
    fprintf(stderr, "memset: %s: memcache error %s",
            key, memcached_strerror(memc, rc));
    if (memc->cached_errno)
      fprintf(stderr, " system error %s", strerror(memc->cached_errno));
    fprintf(stderr, "\n");
  }
  memcached_free(memc);
  return(0);
}

サーバを二つたてて実験してみます.

> ./a.out 127.0.0.1:11211,127.0.0.1:11212 key val
[11211]
(無言)
[11212]
<18 new auto-negotiating client connection
18: Client using the ascii protocol
<18 set key 0 0 3
>18 STORED
<18 quit
<18 connection closed.

読み出してみます.

> memcat --servers=127.0.0.1:11211,127.0.0.1:11212 key
val
[11211]
(無言)
[11212]
<18 new auto-negotiating client connection
18: Client using the ascii protocol
<18 get key
>18 sending key key
>18 END
<18 quit
<18 connection closed.

Ok. サーバを2台指定してクラスタリングしたけど,ハッシュで1台にしかアクセスが行かない普通の動作です.

さて,いよいよlibmemcachedのレプリケーションを実装します.プログラムはこんな感じです.

#include <libmemcached/memcached.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
  memcached_st *memc;
  memcached_return rc;
  memcached_server_st *servers;
  char *key, *val;

  memc= memcached_create(NULL);

  servers= memcached_servers_parse(argv[1]);
  key = argv[2];
  val = argv[3];

  memcached_server_push(memc, servers);
  memcached_server_list_free(servers);

  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BINARY_PROTOCOL, 1);  // 重要!バイナリプロトコル必須
  memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS,
                         (uint64_t)1); // 重要!レプリケーション数必須

  rc= memcached_set(memc, key, strlen(key),val, strlen(val), 0, 0);

  if (rc != MEMCACHED_SUCCESS)
  {
    fprintf(stderr, "memset: %s: memcache error %s",
            key, memcached_strerror(memc, rc));
    if (memc->cached_errno)
      fprintf(stderr, " system error %s", strerror(memc->cached_errno));
    fprintf(stderr, "\n");
  }
  memcached_free(memc);
  return(0);
}

コンパイルと,あとmemcachedも,一度全部再起動します.

> cc -I/usr/local/include memset.c -L/usr/local/lib -lmemcached
# memcached -vv -p 11211 -u nobody
# memcached -vv -p 11212 -u nobody

じゃ,実行します.

> ./a.out 127.0.0.1:11211,127.0.0.1:11212 key val
[11211]
<18 new auto-negotiating client connection
18: Client using the binary protocol
<18 Read binary protocol data:
<18    0x80 0x11 0x00 0x03
<18    0x08 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x0e
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18 SET key Value len is 3
<18 Read binary protocol data:
<18    0x80 0x07 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
>18 Writing bin response:
>18   0x81 0x07 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x00
<18 connection closed.
[11212]
<18 new auto-negotiating client connection
18: Client using the binary protocol
<18 Read binary protocol data:
<18    0x80 0x01 0x00 0x03
<18    0x08 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x0e
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18 SET key Value len is 3
>18 Writing bin response:
>18   0x81 0x01 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x01
<18 Read binary protocol data:
<18    0x80 0x07 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
<18    0x00 0x00 0x00 0x00
>18 Writing bin response:
>18   0x81 0x07 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x00
>18   0x00 0x00 0x00 0x00
<18 connection closed.

どちらも反応してます.
読み出してみます.

> memcat --servers=127.0.0.1:11211 key; memcat --servers=127.0.0.1:11212 key
val
val
[11211]
<18 new auto-negotiating client connection
18: Client using the ascii protocol
<18 get key
>18 sending key key
>18 END
<18 quit
<18 connection closed.
[11212]
<18 new auto-negotiating client connection
18: Client using the ascii protocol
<18 get key
>18 sending key key
>18 END
<18 quit
<18 connection closed.

どちらも反応しました...

これはmemcached冗長化に使えそうです.
さっそく,明日...