引入:当一台memcached服务器不能满足我们的要求时,需要布置多台服务器,那么问题来了,怎么确定一个数据该放在哪台服务器上呢?
一般有两种方案,一个是普通hash分布,另一个是一致性hash分布。
1. 普通hash分布
函数如下:
<span style="font-family:Microsoft YaHei;font-size:18px;">functionmHash($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;
}</span>
首先通过md5把key处理成一个32位字符串,取其前8字符。在经过hash算法处理成一个整数并返回,然后映射到另一个memcached服务器。
假设配置两台memcached服务器,可以使用下面代码映射:
<span style="font-family:Microsoft YaHei;font-size:18px;"><?
$servers = array(
array("host" =>"192.168.1.12","port" => 6397),
array("host" =>"192.168.1.20","port" => 6397),
);
$key = "TheKey";
$value = "TheValue";
$sc = servers[mHash($key)%2];
$memcached =new memcached($sc);
$memcached -> set($key,$value);</span>
通过Hash函数把key转化成整数后,利用这个整数与memcached服务器数量取模,这样就得到的是其中的一台服务器的配置,利用这个配置链接memcached服务器,这样就完成了分布式布置,取数据和保存数据的方法一样,把set命令改成get命令就可以了。
2. 一致性Hash分布
在服务器数量不发生改变时,普通的Hash分布可以很好地运作。当服务器的数量发生改变时,问题就出来了,试想,增加一台服务器时,同一个key经过Hash之后,与服务器取模的结果跟没增加服务器之前的结果会不一样,这就导致之前保存的数据丢失。为了把丢失的数据减少到最少,可以采用一致性hash算法。
一致性hash算法分为6个步骤:
步骤1:
将一个32位整数0~2^32-1想象成一个环,将0作为圆环的头,2^32-1作为圆环的尾,把它连接起来。
步骤2:
通过Hash函数把key处理成整数:
<span style="font-family:Microsoft YaHei;"> $key1 = mHash(“key1”);
$key2= mHash(“key2”);
$key3 = mHash(“key3”);
$key4= mHash(“key4”);</span>
把key处理成整数之后,就可以在环中找到一个位置与之对应。
步骤3:
把memcached群映射到环上,使用Hash函数处理服务器所使用的IP地址。
例如有3台服务器,使用下面的方法映射到环上。
<span style="font-family:Microsoft YaHei;"> $server1 = mHash(“192.168.1.1”);
$server2 = mHash(“192.168.1.2”);
$server3 = mHash(“192.168.1.3”);</span>
把服务器映射到环上,如图所示:
经过上面的几个步骤,我们把数据的key和服务器都映射到同一个环上,下面考虑如何把数据映射到服务器上。
步骤4:把数据映射 到服务器上
沿着环顺时针方向的key出发,知道遇到下一个服务器为止,把key对应的数据保存到这个服务器上。根据上面的方法,key4和key3保存到server2上,key2保存到server1上,key1保存到server3上。
步骤5:移除服务器
考虑一下,如果server2服务器崩溃了,那么受最大影响的仅是沿着server2逆时针出发直到下一个服务器之间的数据,也就是映射到server2上的那些数据。然后依照规则,将server2服务器上的数据移植下一个服务器上即可。
步骤6:添加服务器。
再考虑一下,如果要添加一个服务器server4,用之前的方法把它映射到key3和key4之间,这时受到的影响是沿着server4逆时针出发直至遇到下一个服务器之间的数据,把这些数据重新映射到server4上即可。