PHP实现的一致性哈希算法完整实例
本文实例讲述了PHP实现的一致性哈希算法。分享给大家供大家参考,具体如下:
<?php
/**
*Flexihash-AsimpleconsistenthashingimplementationforPHP.
*
*TheMITLicense
*
*Copyright(c)2008PaulAnnesley
*
*Permissionisherebygranted,freeofcharge,toanypersonobtainingacopy
*ofthissoftwareandassociateddocumentationfiles(the"Software"),todeal
*intheSoftwarewithoutrestriction,includingwithoutlimitationtherights
*touse,copy,modify,merge,publish,distribute,sublicense,and/orsell
*copiesoftheSoftware,andtopermitpersonstowhomtheSoftwareis
*furnishedtodoso,subjecttothefollowingconditions:
*
*Theabovecopyrightnoticeandthispermissionnoticeshallbeincludedin
*allcopiesorsubstantialportionsoftheSoftware.
*
*THESOFTWAREISPROVIDED"ASIS",WITHOUTWARRANTYOFANYKIND,EXPRESSOR
*IMPLIED,INCLUDINGBUTNOTLIMITEDTOTHEWARRANTIESOFMERCHANTABILITY,
*FITNESSFORAPARTICULARPURPOSEANDNONINFRINGEMENT.INNOEVENTSHALLTHE
*AUTHORSORCOPYRIGHTHOLDERSBELIABLEFORANYCLAIM,DAMAGESOROTHER
*LIABILITY,WHETHERINANACTIONOFCONTRACT,TORTOROTHERWISE,ARISINGFROM,
*OUTOFORINCONNECTIONWITHTHESOFTWAREORTHEUSEOROTHERDEALINGSIN
*THESOFTWARE.
*
*@authorPaulAnnesley
*@linkhttp://paul.annesley.cc/
*@copyrightPaulAnnesley,2008
*@commentbyMyZ(http://blog.csdn.net/mayongzhan)
*/
/**
*Asimpleconsistenthashingimplementationwithpluggablehashalgorithms.
*
*@authorPaulAnnesley
*@packageFlexihash
*@licencehttp://www.opensource.org/licenses/mit-license.php
*/
classFlexihash
{
/**
*Thenumberofpositionstohasheachtargetto.
*
*@varint
*@comment虚拟节点数,解决节点分布不均的问题
*/
private$_replicas=64;
/**
*Thehashalgorithm,encapsulatedinaFlexihash_Hasherimplementation.
*@varobjectFlexihash_Hasher
*@comment使用的hash方法:md5,crc32
*/
private$_hasher;
/**
*Internalcounterforcurrentnumberoftargets.
*@varint
*@comment节点记数器
*/
private$_targetCount=0;
/**
*Internalmapofpositions(hashoutputs)totargets
*@vararray{position=>target,...}
*@comment位置对应节点,用于lookup中根据位置确定要访问的节点
*/
private$_positionToTarget=array();
/**
*Internalmapoftargetstolistsofpositionsthattargetishashedto.
*@vararray{target=>[position,position,...],...}
*@comment节点对应位置,用于删除节点
*/
private$_targetToPositions=array();
/**
*Whethertheinternalmapofpositionstotargetsisalreadysorted.
*@varboolean
*@comment是否已排序
*/
private$_positionToTargetSorted=false;
/**
*Constructor
*@paramobject$hasherFlexihash_Hasher
*@paramint$replicasAmountofpositionstohasheachtargetto.
*@comment构造函数,确定要使用的hash方法和需拟节点数,虚拟节点数越多,分布越均匀,但程序的分布式运算越慢
*/
publicfunction__construct(Flexihash_Hasher$hasher=null,$replicas=null)
{
$this->_hasher=$hasher?$hasher:newFlexihash_Crc32Hasher();
if(!empty($replicas))$this->_replicas=$replicas;
}
/**
*Addatarget.
*@paramstring$target
*@chainable
*@comment添加节点,根据虚拟节点数,将节点分布到多个虚拟位置上
*/
publicfunctionaddTarget($target)
{
if(isset($this->_targetToPositions[$target]))
{
thrownewFlexihash_Exception("Target'$target'alreadyexists.");
}
$this->_targetToPositions[$target]=array();
//hashthetargetintomultiplepositions
for($i=0;$i<$this->_replicas;$i++)
{
$position=$this->_hasher->hash($target.$i);
$this->_positionToTarget[$position]=$target;//lookup
$this->_targetToPositions[$target][]=$position;//targetremoval
}
$this->_positionToTargetSorted=false;
$this->_targetCount++;
return$this;
}
/**
*Addalistoftargets.
*@paramarray$targets
*@chainable
*/
publicfunctionaddTargets($targets)
{
foreach($targetsas$target)
{
$this->addTarget($target);
}
return$this;
}
/**
*Removeatarget.
*@paramstring$target
*@chainable
*/
publicfunctionremoveTarget($target)
{
if(!isset($this->_targetToPositions[$target]))
{
thrownewFlexihash_Exception("Target'$target'doesnotexist.");
}
foreach($this->_targetToPositions[$target]as$position)
{
unset($this->_positionToTarget[$position]);
}
unset($this->_targetToPositions[$target]);
$this->_targetCount--;
return$this;
}
/**
*Alistofallpotentialtargets
*@returnarray
*/
publicfunctiongetAllTargets()
{
returnarray_keys($this->_targetToPositions);
}
/**
*Looksupthetargetforthegivenresource.
*@paramstring$resource
*@returnstring
*/
publicfunctionlookup($resource)
{
$targets=$this->lookupList($resource,1);
if(empty($targets))thrownewFlexihash_Exception('Notargetsexist');
return$targets[0];
}
/**
*Getalistoftargetsfortheresource,inorderofprecedence.
*Upto$requestedCounttargetsarereturned,lessiftherearefewerintotal.
*
*@paramstring$resource
*@paramint$requestedCountThelengthofthelisttoreturn
*@returnarrayListoftargets
*@comment查找当前的资源对应的节点,
*节点为空则返回空,节点只有一个则返回该节点,
*对当前资源进行hash,对所有的位置进行排序,在有序的位置列上寻找当前资源的位置
*当全部没有找到的时候,将资源的位置确定为有序位置的第一个(形成一个环)
*返回所找到的节点
*/
publicfunctionlookupList($resource,$requestedCount)
{
if(!$requestedCount)
thrownewFlexihash_Exception('Invalidcountrequested');
//handlenotargets
if(empty($this->_positionToTarget))
returnarray();
//optimizesingletarget
if($this->_targetCount==1)
returnarray_unique(array_values($this->_positionToTarget));
//hashresourcetoaposition
$resourcePosition=$this->_hasher->hash($resource);
$results=array();
$collect=false;
$this->_sortPositionTargets();
//searchvaluesabovetheresourcePosition
foreach($this->_positionToTargetas$key=>$value)
{
//startcollectingtargetsafterpassingresourceposition
if(!$collect&&$key>$resourcePosition)
{
$collect=true;
}
//onlycollectthefirstinstanceofanytarget
if($collect&&!in_array($value,$results))
{
$results[]=$value;
}
//returnwhenenoughresults,orlistexhausted
if(count($results)==$requestedCount||count($results)==$this->_targetCount)
{
return$results;
}
}
//looptostart-searchvaluesbelowtheresourcePosition
foreach($this->_positionToTargetas$key=>$value)
{
if(!in_array($value,$results))
{
$results[]=$value;
}
//returnwhenenoughresults,orlistexhausted
if(count($results)==$requestedCount||count($results)==$this->_targetCount)
{
return$results;
}
}
//returnresultsafteriteratingthroughboth"parts"
return$results;
}
publicfunction__toString()
{
returnsprintf(
'%s{targets:[%s]}',
get_class($this),
implode(',',$this->getAllTargets())
);
}
//----------------------------------------
//privatemethods
/**
*Sortstheinternalmapping(positionstotargets)byposition
*/
privatefunction_sortPositionTargets()
{
//sortbykey(position)ifnotalready
if(!$this->_positionToTargetSorted)
{
ksort($this->_positionToTarget,SORT_REGULAR);
$this->_positionToTargetSorted=true;
}
}
}
/**
*Hashesgivenvaluesintoasortablefixedsizeaddressspace.
*
*@authorPaulAnnesley
*@packageFlexihash
*@licencehttp://www.opensource.org/licenses/mit-license.php
*/
interfaceFlexihash_Hasher
{
/**
*Hashesthegivenstringintoa32bitaddressspace.
*
*Notethattheoutputmaybemorethan32bitsofrawdata,forexample
*hexidecimalcharactersrepresentinga32bitvalue.
*
*Thedatamusthave0xFFFFFFFFpossiblevalues,andbesortableby
*PHPsortfunctionsusingSORT_REGULAR.
*
*@paramstring
*@returnmixedAsortableformatwith0xFFFFFFFFpossiblevalues
*/
publicfunctionhash($string);
}
/**
*UsesCRC32tohashavalueintoasigned32bitintaddressspace.
*Under32bitPHPthis(safely)overflowsintonegativesints.
*
*@authorPaulAnnesley
*@packageFlexihash
*@licencehttp://www.opensource.org/licenses/mit-license.php
*/
classFlexihash_Crc32Hasher
implementsFlexihash_Hasher
{
/*(non-phpdoc)
*@seeFlexihash_Hasher::hash()
*/
publicfunctionhash($string)
{
returncrc32($string);
}
}
/**
*UsesCRC32tohashavalueintoa32bitbinarystringdataaddressspace.
*
*@authorPaulAnnesley
*@packageFlexihash
*@licencehttp://www.opensource.org/licenses/mit-license.php
*/
classFlexihash_Md5Hasher
implementsFlexihash_Hasher
{
/*(non-phpdoc)
*@seeFlexihash_Hasher::hash()
*/
publicfunctionhash($string)
{
returnsubstr(md5($string),0,8);//8hexits=32bit
//4bytesofbinarymd5datacouldalsobeused,but
//performanceseemstobethesame.
}
}
/**
*AnexceptionthrownbyFlexihash.
*
*@authorPaulAnnesley
*@packageFlexihash
*@licencehttp://www.opensource.org/licenses/mit-license.php
*/
classFlexihash_ExceptionextendsException
{
}
希望本文所述对大家PHP程序设计有所帮助。