https://blog.phpha.com/backup/archives/1303.html
当Memcached服务器数量固定时,普通Hash分布可以很好的运作。但是当服务器数量发生改变时,问题就出来了。因为同一个KEY经Hash算法处理后,与服务器数量取模,会导致结果与服务器数量未变化时不同,这就导致之前保存的数据丢失。采取一致性Hash分布可以有效的解决这个问题,把丢失的数据减到最小(注意这里并没有说完全不丢失)。
一致性Hash分布算法分4个步骤:
步骤1:将一个32位整数[0 ~ (2^32-1)]想象成一个环,0 作为开头,(2^32-1) 作为结尾,当然这只是想象。
步骤2:通过Hash函数把KEY处理成整数。这样就可以在环上找到一个位置与之对应。
步骤3:把Memcached服务器群映射到环上,使用Hash函数处理服务器对应的IP地址即可。
步骤4:把数据映射到Memcached服务器上。查找一个KEY对应的Memcached服务器位置的方法如下:从当前KEY的位置,沿着圆环顺时针方向出发,查找位置离得最近的一台Memcached服务器,并将KEY对应的数据保存在此服务器上。
说明:这样一来,当添加或移除某一台服务器时,受影响的数据范围变的更小了。具体可以画个图更便于理解,这里我就不画了。
[3]一致性Hash分布算法实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
<?php
/**
* 一致性Hash分布
* 天涯PHP博客
* http://blog.phpha.com
*/
class
FlexiHash
{
//服务器列表
private
$serverList
=
array
(
)
;
//记录是否已经排序
private
$isSorted
=
FALSE
;
//添加一台服务器
public
function
addServer
(
$server
)
{
$hash
=
$this
->
mHash
(
$server
)
;
if
(
!
isset
(
$this
->
serverList
[
$hash
]
)
)
{
$this
->
serverList
[
$hash
]
=
$server
;
}
//需要重新排序
$this
->
isSorted
=
FALSE
;
return
TRUE
;
}
//移除一台服务器
public
function
removeServer
(
$server
)
{
$hash
=
$this
->
mHash
(
$server
)
;
if
(
isset
(
$this
->
serverList
[
$hash
]
)
)
{
unset
(
$this
->
serverList
[
$hash
]
)
;
}
//需要重新排序
$this
->
isSorted
=
FALSE
;
return
TRUE
;
}
//在当前服务器列表查找合适的服务器
public
function
lookup
(
$key
)
{
$hash
=
$this
->
mHash
(
$key
)
;
//先进行倒序排序操作
if
(
!
$this
->
isSorted
)
{
krsort
(
$this
->
serverList
,
SORT_NUMERIC
)
;
$this
->
isSorted
=
TRUE
;
}
//圆环上顺时针方向查找当前KEY紧邻的一台服务器
foreach
(
$this
->
serverList
as
$pos
=
>
$server
)
{
if
(
$hash
>=
$pos
)
return
$server
;
}
//没有找到则返回顺时针方向最后一台服务器
return
$this
->
serverList
[
count
(
$this
->
serverList
)
-
1
]
;
}
//Hash函数
private
function
mHash
(
$key
)
{
$md5
=
substr
(
md5
(
$key
)
,
0
,
8
)
;
$seed
=
31
;
$hash
=
0
;
for
(
$i
=
0
;
$i
<
8
;
$i
++
)
{
$hash
=
$hash
*
$seed
+
ord
(
$md5
{
$i
}
)
;
$i
++
;
}
return
$hash
&
0x7FFFFFFF
;
}
}
?>
|
说明:其整体查找思路,已经在前面的一致性Hash分布部分进行了介绍,需要补充的是每次添加或移除服务器后需要对服务器列表这个序列就行一次排序。
下面是对上面的一致性Hash分布实例的相关测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
<?php
/**
* 一致性Hash分布测试代码
* 天涯PHP博客
* http://blog.phpha.com
*/
$hserver
=
new
FlexiHash
(
)
;
//初始5台服务器
$hserver
->
addServer
(
"192.168.1.1"
)
;
$hserver
->
addServer
(
"192.168.1.2"
)
;
$hserver
->
addServer
(
"192.168.1.3"
)
;
$hserver
->
addServer
(
"192.168.1.4"
)
;
$hserver
->
addServer
(
"192.168.1.5"
)
;
echo
"save key1 in server: "
,
$hserver
->
lookup
(
'key1'
)
,
"<br/>"
;
echo
"save key2 in server: "
,
$hserver
->
lookup
(
'key2'
)
,
"<br/>"
;
echo
'===============================================<br/>'
;
//移除1台服务器
$hserver
->
removeServer
(
"192.168.1.4"
)
;
echo
"save key1 in server: "
,
$hserver
->
lookup
(
'key1'
)
,
"<br/>"
;
echo
"save key2 in server: "
,
$hserver
->
lookup
(
'key2'
)
,
"<br/>"
;
echo
'===============================================<br/>'
;
//添加1台服务器
$hserver
->
addServer
(
'192.168.1.6'
)
;
echo
"save key1 in server: "
,
$hserver
->
lookup
(
'key1'
)
,
"<br/>"
;
echo
"save key2 in server: "
,
$hserver
->
lookup
(
'key2'
)
;
?>
//测试结果如下:
save
key1
in
server
:
192.168.1.4
save
key2
in
server
:
192.168.1.2
===
===
===
===
===
===
===
===
===
===
===
=
save
key1
in
server
:
192.168.1.3
save
key2
in
server
:
192.168.1.2
===
===
===
===
===
===
===
===
===
===
===
=
save
key1
in
server
:
192.168.1.3
save
key2
in
server
:
192.168.1.2
|