一致性哈希算法簡單分析及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;
        }
    }
}

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