memcached 分布式 一致性hash算法demo
一致性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对应的数据保存在此服务器上。
代码实例:
<?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; } } ?>
测试:
<?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