- 一致性哈希算法原理
首先将所有哈希值空间组成一个虚拟的圆环。
其次我们将所有载体(服务器或者数据表)使用某个hash算法,这样就可以找到载体在圆环上的位置。
接下来对要定位的数据使用与载体相同的hash算法,计算出数据在圆环上的位置,然后顺时针去行走到的第一个载体就是其应该定位到的载体。
如果,删除一个载体,那么需要定位的数据会落到,被删除的载体前面的那个载体上。如图:
如果,增加一个载体,效果如图:
相比于hash算法取模运算,一致性hash算法的好处在于,在增加或减少载体的时候,hash只是将该载体前的载体。
如果载体过少,可能会出现数据严重偏移的情况,这种情况我们可以设置多个虚拟节点,每个虚拟节点会对应相应的载体。比如载体1A,载体1B,载体1C,载体2A,载体2B,载体2C,载体3A,载体3B,载体3C,载体4A,载体4B,载体4C。
我们可以将数据定位到这些虚拟节点上,然后,找到虚拟节点所对应的载体。即可定位到数据所在的载体。
- php代码实现
<?php
/**
* 具体一致性哈希算法实现
*
*/
class Hashrealize{
//载体列表
public $carrierList = array();
//节点列表
public $virtualNodeList = array();
//每个载体虚拟节点数量
public $virtualNumber = 5;
/**
* hash算法
*/
private function hashAlgorithm($key){
$string = md5($key);
return sprintf('%u', crc32($string));
}
/**
* 查找节点
*/
public function lookNode($key){
$string = $this->hashAlgorithm($key);
$carrier = '';
foreach($this->virtualNodeList as $hashStringVirtual =>$val){
if($string < $hashStringVirtual){
$carrier = $val;
break;
}
}
return $carrier;
}
/**
* 添加载体
*/
public function addCarrier($carrier){
if(!$this->carrierList[$carrier]){
$hashString = $this->hashAlgorithm($carrier);
for($i=0;$i<$this->virtualNumber;$i++){
$hashStringVirtual = $this->hashAlgorithm($carrier.'_'.$i);
$this->virtualNodeList[$hashStringVirtual] = $carrier;
$this->carrierList[$carrier][] = $hashStringVirtual;
}
ksort($this->virtualNodeList,SORT_NUMERIC);
}
if($this->carrierList[$carrier]){
return true;
}else{
return false;
}
}
/**
* 移除载体
*/
public function removeCarrier($carrier){
if($this->carrierList[$carrier]){
foreach($this->virtualNodeList[$carrier] as $key =>$val){
unset($this->virtualNodeList[$carrier][$key]);
}
unset($this->carrierList[$carrier]);
}
}
}