Consistent Hashingを計算してみる

libmemcachedを流用して,こんなコマンドラインプログラムを書いてみました.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char *argv[])
{
  if(argc<2)
  {
    printf("usage: %s string\n",argv[0]);
    exit(0);
  }
  if(sizeof(unsigned int)!=4)
  {
    printf("please replace unsigned int for 32bit type\n");
    exit(0);
  }
  int key_len = strlen(argv[1]);
  char *key = (char *)malloc(key_len+1); /* for CR */
  strcpy(key, argv[1]);
  unsigned int value= 0;

  while (key_len--)
  {
    unsigned int val= (unsigned int) *key++;
    value += val;
    value += (value << 10);  // value += value *= 2^10
    value ^= (value >> 6);
  }
  value += (value << 3);
  value ^= (value >> 11);
  value += (value << 15);

  unsigned int hash_value = value == 0 ? 1 : (unsigned int) value;
  printf("hash = %u\n",hash_value);
  return(0);
}

コンパイルして実行します.

> cc generate_default_consistent_hashing.c

まず,3つのmemcachedサーバがあるとします.そのホスト名でハッシュを計算します.

> ./a.out localhost01
hash = 2484904651
> ./a.out localhost02
hash = 378546096
> ./a.out localhost03
hash = 266803806

これをハッシュ値で並べてみると,ホストは次のように並べられていることに相当します.

[0] <-(A)-> localhost03[266803806] <-(B)-> localhost02[378546096] <-(C)-> localhost01[2484904651] <-(D)-> [4294967295]

(A)はlocalhost03に,(B)はlocalhost02に,(C)はlocalhost01に,(D)は,コンシステント・ハッシングはトーラス状に並ぶと考えるそうなので[0]と繋がっていると考え,やはりlocalhost03にストアされます.

適当なキーでハッシュを計算してみます.

> ./a.out key1
hash = 3203718188 --> (D)=(A)=localhost03
> ./a.out key2
hash = 2905880747 --> (D)=(A)=localhost03
> ./a.out key3
hash = 3682768199 --> (D)=(A)=localhost03
> ./a.out key4
hash = 3386175980 --> (D)=(A)=localhost03
> ./a.out key5
hash = 4101556019 --> (D)=(A)=localhost03

なんと全てのキーがlocalhost03にストアされることになりました.localhost03の負荷が高そうですね.
でも,localhost01やlocalhost02が落ちても,バリューは消えずにすむようです.localhost03が落ちると,キャッシュは全部構築し直しです.


もう少し複雑なキーでハッシュを計算してみます.

> ./a.out yahoo.co.jp
hash = 1591825169 --> (C)=localhost01
> ./a.out rakuten.co.jp
hash = 2584871479 --> (D)=(A)=localhost03
> ./a.out amazon.co.jp
hash = 3280703220 --> (D)=(A)=localhost03
> ./a.out msn.co.jp
hash = 2112415372 --> (C)=localhost01
> ./a.out google.co.jp
hash = 1868171465 --> (C)=localhost01

この場合,localhost01が落ちると3/5のキャッシュが構築し直し,localhost02が落ちても影響なし,localhost03が落ちると2/5のキャッシュが構築し直しになるようです.

その他のパターンは,また次回に.