一致性哈希算法简单分析及php实现

网上已有多篇很详细的概念,这里不做赘述,简要说下自己关于一致性哈希算法的想法:

1.平凡hash算法

首先是hash算法,这里之前在学校习惯的取模算法并不可取。原因在于当整个hash空间的节点增加或者删除时,会导致所有节点的hash重新计算,导致了不单调。我在代码中选取了DJBX33A算法,该算法是对字符串而言目前已知的最好哈希算法。

2.hash空间

这里举一个简单的hash空间为例说明:该hash空间是个环形hash,避免单调性的问题,其次可以保证每一个输入进来的object在有target的存在下都会找到最靠近其的target.

3.映射

在该算法中需要操作的一个是object,一个是node,object是需要输入保存的信息,而node是缓存计算机节点。均通过hash函数来计算其hash值,并存于hash空间中。

4.节点的增删

         毫无疑问,在hash算法中会面临缓存计算机down掉或者新加入一台缓存计算机,所以节点的增删对hash空间的影响应尽可能的小。

图中,node4节点被移除,则原本存于其的obj3进而找到距离其顺指针方向最近的node1,从而存在了node1中。

而在该图中,新加入了一个node5节点,则原本归属于node1的obj4归并到node5中。

5.虚拟节点

         虚拟节点的作用在于,当down掉过多的相邻计算机,而增加了某个或某几个节点的负担时,可以通过虚拟节点来平衡其负载。原理是,将每一台服务器计算机当做一个虚拟计算机群。将原来的一个节点例如node1,分为node1.1, node1.2, node1.3并加入到原hash空间中。使得每一台计算机负载尽可能平衡。

6.冗余

         在参考别人实现的时候发现冗余是将其归属的node之后几个节点均储存其object信息。觉得合理。



<?php
/**
 * Created by PhpStorm.
 * User: Jason  D
 * Date: 2016/4/15
 * Time: 13:39
 */
functionssHash($str) {
   
$hash = 0;
   
$s   =md5($str);
   
$seed = 5;
   
$len = 32;
   
for ($i = 0; $i < $len; $i++) {
       
$hash = ($hash << $seed) + $hash + ord($s{$i});
    }

   
return $hash & 0x7FFFFFFF;
}
class Flexihash
{
   
private $_replicas = 1;

   
private $_targetCount = 0;

   
private $_positionToTarget = array();

   
private $_targetToPositions = array();

   
public $_sourceToPositions = array();

   
private $_targetsource = array();

   
private $_isSorted = false;

   
public function setReplicas($replicas)
    {
       
$this->_replicas = $replicas;
    }
   
public function addsource($source)
    {
       
$hash = ssHash($source);
       
if(!isset($this->_sourceToPositions[$hash]))
           
$this->_sourceToPositions[$hash] = $source;
       
return $this;
    }

   
public function removeSource($source)
    {
       
$hash = ssHash($source);
       
if(isset($this->_sourceToPositions[$hash]))
           
unset($this->_sourceToPositions[$hash]);
       
$target = $this->find($source);
       
for($i = 0; $i < cout($this->_targetsource); $i++)
        {
           
if($this->_targetsource[$i] == $source)
               
unset($this->_targetsource[$i]);
        }
    }
   
public function addTarget($target)
    {
       
if(isset($this->_targetToPositions[$target]))
        {
          
echo"this Target alreadyexists.";
        }

       
$this->_targetToPositions[$target] = array();
       
for($i = 0; $i < $this->_replicas; $i++)
        {
           
$position = ssHash($target . $i);
           
$this->_positionToTarget[$position] = $target;
           
$this->_targetToPositions[$target][] = $position;
        }

       
$this->_isSorted = false;
       
$this->_targetCount ++;
       
return $this;
    }

   
public function addTargets($targets)
    {
       
foreach($targets as $target)
        {
            addTarget(
$target);
        }
       
return $this;
    }

   
public function removeTarget($target)
    {
       
if(!isset($this->_targetToPositions[$target]))
        {
           
echo "this Target does notexist.";
        }
       
foreach($this->_targetToPositions[$target] as $position)
        {
           
unset($this->_positionToTarget[$position]);
        }

       
unset($this->_targetToPositions[$target]);
       
$this->_targetCount--;
       
return $this;
    }

   
public function getAllTargets()
    {
       
return array_keys($this->_targetToPositions);
    }

   
public function lookup($resource)
    {
       
$targets = $this->lookupList($resource, 1);
       
if(empty($targets))
           
echo "No targets exist";
       
return $targets[0];
    }

   
public function find()
    {
       
foreach($this->_sourceToPositions as $key => $value)
        {
           
$target = lookup($value);
           
if(empty($target))
               
echo "no targetexist";
           
$this->_targetsource[$target] = array();
           
$_targetsource[$target][] = $value;
        }
       
return $target;
    }

   
public function lookupList($resource, $requestedCount)
    {
       
if(!$requestedCount)
           
echo "Invalid count requested";

       
if(empty($this->_positionToTarget))
           
return array();

       
if($this->_targetCount == 1)
           
return array_unique(array_values($this->_positionToTarget));

       
$resourcePosition = ssHash($resource);

       
$results = array();
       
$collect = false;

       
$this->_sortPositionTargets();

       
foreach($this->_positionToTarget as $key => $value)
        {
           
if(!$collect && $key > $resourcePosition)
            {
               
$collect = true;
            }
           
if($collect && !in_array($value, $results))
            {
               
$results [] = $value;
            }

           
if(count($results) == $requestedCount || count($results) == $this->_targetCount)
            {
               
return $results;
            }
        }
       
return $results;
    }

   
private function _sortPositionTargets()
    {
       
if(!$this->_isSorted)
        {
            ksort(
$this->_positionToTarget, SORT_REGULAR);
           
$this->_isSorted = true;
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章