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);
        }
    }
}

 

 

posted @ 2018-04-26 14:19  爱读书的小明  阅读(87)  评论(0编辑  收藏  举报