关于Memcached一致性hash的探究

参考文章

http://blog.chinaunix.net/uid-20498361-id-4303232.html

http://blog.csdn.net/kongqz/article/details/6695417

https://my.oschina.net/goal/blog/203593?p=1

一直认为一致性hash是个很神奇的东东,技术大牛的想法果然不同凡响。

 

下列代码并没有作优化处理,仅供参考理解ketama算法,当然也有助于自己理解记忆。如果有错误的地方欢迎指出

 1 function addServer($hostName = array()){
 2     $serverList = array();
 3     foreach($hostName as $val) {
 4         for($i = 0;$i<40;$i++) {
 5             $digest = md5($val.'_'.$i, true);
 6             for ($h = 0; $h < 4; $h++) {
 7                 $hash = (ord($digest[3 + $h * 4]) << 24) | (ord($digest[2 + $h * 4]) << 16)
 8                     | (ord($digest[1 + $h * 4]) << 8) | ord($digest[$h * 4]);
 9                 $serverList[$val][$i*4+$h] = $hash;
10             }
11         }
12     }
13     return $serverList;
14 }
15 //md5的原因是怕用户输入前缀一致  hash一样  分布不均匀??
16 function getKeyHash($str){
17     $digest = md5($str,1);
18     return (ord($digest[3])<<24) | (ord($digest[2])<<16) | (ord($digest[3])<<8) | (ord($digest[0]));
19 }
20 
21 
22 function findKey($str){
23     $hostName = array(
24         '10.100.20.1',
25         '10.100.20.2',
26         '10.100.20.3',
27         '10.100.20.4',
28         '10.100.20.5',
29         '10.100.20.6',
30     );
31     $serverList  = addServer($hostName);
32     $serverHash = array();
33     foreach($serverList as $server){
34         $serverHash = array_merge($serverHash,$server);
35     }
36     sort($serverHash);
37     $i = 0;
38     $len = count($serverHash);
39     $keyHash = getKeyHash($str);
40     if($keyHash>$serverHash[$len-1]){
41         foreach($serverList as $key=>$val){
42             if(in_array($serverHash[$len-1],$val)){
43                 return $key;
44             }
45         }
46         return 0;
47     }
48     while($i<$len){
49         $curr = $serverHash[$i];
50         $next = $serverHash[++$i];
51         if($next>=$keyHash && $keyHash>=$curr){
52             foreach($serverList as $key=>$val){
53                 if(in_array($serverHash[$i],$val)){
54                     return $key;
55                 }
56             }
57         }
58     }
59     return false;
60 }
61 $result = array();
62 for($i=1;$i<1000;$i++){
63     $tmp = findKey('key'.$i);
64     if(isset($result[$tmp])){
65         $result[$tmp]++;
66     }else{
67         $result[$tmp] = 0;
68     }
69 }
70 print_r($result);

 上面输出结果如下,所以说该算法分布还是相当均匀的。

[root@silence suanfa]# php ketama.php
Array
(
[10.100.20.6] => 149
[10.100.20.5] => 162
[10.100.20.4] => 171
[10.100.20.2] => 146
[10.100.20.3] => 196
[10.100.20.1] => 169
)

查找键值所在服务器可以采用下列折半的方式

 1 $rangeArr =
 2 array (
 3     0 => 19,
 4     1 => 99,
 5     2 => 47,
 6     3 => 49,
 7     4 => 74,
 8     5 => 77,
 9     6 => 45,
10     7 => 95,
11     8 => 87,
12     9 => 15,
13     10 => 14,
14     11 => 29,
15     12 => 57,
16     13 => 3,
17     14 => 8,
18     15 => 38,
19     16 => 28,
20     17 => 67,
21     18 => 55,
22     19 => 43,
23     20 => 5,
24     21 => 25,
25     22 => 48,
26     23 => 32,
27     24 => 58,
28     25 => 90,
29     26 => 27,
30     27 => 50,
31     28 => 6,
32     29 => 63,
33     30 => 65,
34     31 => 81,
35     32 => 51,
36     33 => 52,
37     34 => 66,
38     35 => 30,
39     36 => 56,
40     37 => 54,
41     38 => 86,
42     39 => 84,
43     40 => 83,
44     41 => 64,
45     42 => 42,
46     43 => 26,
47     44 => 46,
48     45 => 79,
49     46 => 69,
50     47 => 98,
51     48 => 24,
52     49 => 37,
53 );
54 sort($rangeArr);
55 function findPoint($num,$rangeArr){
56     $len = count($rangeArr);
57     if($num> $rangeArr[$len-1] || $num<$rangeArr[0]){
58         return $num.'in'.$rangeArr[0];
59     }
60     if($len == 2){
61         return $num.'in'.$rangeArr[1];
62     }
63     if($len == 1){
64         return $num.'in'.$rangeArr[0];
65     }
66     $half  =(int)floor($len/2);
67     if($num<$rangeArr[$half]){
68         $tmp = array_slice($rangeArr,0,$half+1);
69         return findPoint($num,$tmp);
70     }else{
71         $tmp = array_slice($rangeArr,$half,$len-$half);
72         return findPoint($num,$tmp);
73     }
74 }
75 echo findPoint(4,$rangeArr);exit;

 

posted on 2017-01-04 18:27  爱搁浅  阅读(162)  评论(0编辑  收藏  举报