Memcached 笔记与总结(6)PHP 实现 Memcached 的一致性哈希分布算法
首先创建一个接口,有 3 个方法:
addServer:添加一个服务器到服务器列表中
removeServer:从服务器列表中移除一个服务器
lookup:在当前的服务器列表中找到合适的服务器存放数据
interface distribute{ //在当前的服务器列表中找到合适的服务器存放数据 public function lookup($key); //添加一个服务器到服务器列表中 public function addServer($server); //从服务器列表中删除一个服务器 public function removeServer($server); }
再定义一个接口把字符串转换为整数:
interface hash{ public function _hash($str); }
创建类 consistentHash 继承以上两个接口,它有两个成员变量:
$serverList:保存的服务器列表
$isSorted:记录服务器列表是否已经排列过序
addServer 方法的实现:
public function addServer($server){ $hash = $this->_hash($server); if (!isset($this->serverList[$hash])) { //通过此Hash值定位服务器列表上的某个位置 $this->serverList[$hash] = $server; } //此时服务器列表发生了变化,因此标识为FALSE $this->isSorted = FALSE; return TRUE; }
removeServer 方法的实现:
public function removeServer($server){ $hash = $this->_hash($server); if (isset($this->serverList[$hash])) { unset($this->serverList[$hash]); } $this->isSorted = FALSE; return TRUE; }
lookup 方法的实现:
public function lookup($key){ //计算出服务器的Hash值 $hash = $this->_hash($key); //判断服务器列表是否排过序 if (!$this->isSorted) { //倒序排列(把服务器列表装换成逆时针圆环) krsort($this->serverList, SORT_NUMERIC); $this->isSorted = TRUE; } //遍历服务器列表,找到合适的服务器并返回 foreach($this->serverList as $pos => $server){ if ($hash >= $pos) return $server; } return end($this->serverList); }
完整代码:
<?php //把字符串转换为整数 interface hash{ public function _hash($str); } interface distribute{ //在当前的服务器列表中找到合适的服务器存放数据 public function lookup($key); //添加一个服务器到服务器列表中 public function addServer($server); //从服务器列表中删除一个服务器 public function removeServer($server); } class consistentHash implements hash, distribute{ private $serverList = array();//保存的服务器列表 private $isSorted = FALSE; //记录服务器列表是否已经排列过序 public function _hash($str){ return sprintf('%u', crc32($str));//把字符串转成32为无符号整数 } public function lookup($key){ //计算出服务器的Hash值 $hash = $this->_hash($key); //判断服务器列表是否排过序 if (!$this->isSorted) { //倒序排列(把服务器列表转换成逆时针圆环) krsort($this->serverList, SORT_NUMERIC); $this->isSorted = TRUE; } //遍历服务器列表,找到合适的服务器并返回 foreach($this->serverList as $pos => $server){ if ($hash >= $pos) return $server; } return end($this->serverList); } public function addServer($server){ $hash = $this->_hash($server); if (!isset($this->serverList[$hash])) { //通过此Hash值定位服务器列表上的某个位置 $this->serverList[$hash] = $server; } //此时服务器列表发生了变化,因此标识为FALSE $this->isSorted = FALSE; return TRUE; } public function removeServer($server){ $hash = $this->_hash($server); if (isset($this->serverList[$hash])) { unset($this->serverList[$hash]); } $this->isSorted = FALSE; return TRUE; } } $hashserver = new consistentHash(); $hashserver->addServer('192.168.1.1'); $hashserver->addServer('192.168.1.2'); $hashserver->addServer('192.168.1.3'); $hashserver->addServer('192.168.1.4'); $hashserver->addServer('192.168.1.5'); echo 'save key1 on server:',$hashserver->lookup('key1'),'<br />'; echo 'save key2 on server:',$hashserver->lookup('key2'),'<br />'; echo '=======================<br /><br />'; $hashserver->removeServer('192.168.1.2'); echo 'save key1 on server:',$hashserver->lookup('key1'),'<br />'; echo 'save key2 on server:',$hashserver->lookup('key2'),'<br />'; echo '=======================<br /><br />'; $hashserver->addServer('192.168.1.6'); echo 'save key1 on server:',$hashserver->lookup('key1'),'<br />'; echo 'save key2 on server:',$hashserver->lookup('key2'),'<br />'; echo '=======================<br /><br />';
输出:
save key1 on server:192.168.1.2 save key2 on server:192.168.1.5 ======================= save key1 on server:192.168.1.3 save key2 on server:192.168.1.5 ======================= save key1 on server:192.168.1.6 save key2 on server:192.168.1.5 =======================
结论:在增加或减少服务器的时候,一致性 Hash 算法只会改变很少一部分数据的存储服务器,从而减少了数据丢失的情况。