php实现一致性hash算法
使用php实现一致性hash算法
<?php
use Flexihash\Hasher\HasherInterface;
use Flexihash\Hasher\Crc32Hasher;
use Flexihash\Exception;
/**
* 参考:https://github.com/pda/flexihash
* 一致性哈希算法实现
* Class MyFlexiHash
* 主要的方法有三个:addTarget、removeTarget、lookupList,其它都是语法糖
* lookupList(key)的实现方式是在一个有序列表上先搜索大于key的部分,数量不够再从头选取元素进行补充
*/
class MyFlexiHash {
private $replicas = 64;
private $hasher = null;
private $positionTargetMap = array();
private $targetPositionsMap = array();
public function __construct(HasherInterface $hasher = null, $replicas = null)
{
$this->hasher = isset($hasher) ? $hasher : new Crc32Hasher();
isset($replicas) && $this->replicas = $replicas;
}
public function addTarget($target, $weight = 1) {
$positions = array();
$existPositions = array_keys($this->positionTargetMap);
for ($i = 0; $i < $this->replicas * $weight; $i++) {
//find an position not in exist positions
$suffix = '';
do {
$suffix .= $i;
$position = $this->hasher->hash($target.''.$suffix);
} while (in_array($position, $existPositions));
//record position's target
$this->positionTargetMap[$position] = $target;
//collect position
$positions[] = $position;
}
//sort position
ksort($this->positionTargetMap);
//record target's positions
$this->targetPositionsMap[$target] = $positions;
}
public function removeTarget($target) {
if (!isset($this->targetPositionsMap[$target])) {
throw new Exception('remove not exists target: '.$target);
}
$positions = $this->targetPositionsMap[$target];
//remove target's positions
unset($this->targetPositionsMap[$target]);
//remove position's target
foreach ($positions as $position) {
unset($this->positionTargetMap[$position]);
}
}
public function lookup($resource) {
return $this->lookupList($resource, 1)[0];
}
public function lookupList($resource, $count) {
if ($this->isTargetsEmpty()) {
throw new Exception('lookup targets empty');
}
if ($count > count($this->targetPositionsMap)) {
throw new Exception('lookup targets not enough');
}
$targetList = array();
$hash = $this->hasher->hash($resource);
//find in the above positions
foreach ($this->positionTargetMap as $position => $t) {
if (count($targetList) == $count) {
break;
}
if ($hash >= $position) {
$targetList[] = $t;
}
}
//find in the below positions
if (count($targetList) < $count) {
foreach ($this->positionTargetMap as $position => $t) {
if (count($targetList) == $count) {
break;
}
$targetList[] = $t;
}
}
return $targetList;
}
public function isTargetsEmpty() {
return count($this->targetPositionsMap) == 0;
}
public function addTargets($targets) {
foreach ($targets as $target) {
$this->addTarget($target);
}
}
public function removeTargets($targets) {
foreach ($targets as $target) {
$this->removeTarget($target);
}
}
}
浙公网安备 33010602011771号