一致性哈希的算法把取餘算法的等於號來選擇mem服務器變成了大於號來選擇mem服務器,這應該是纔是關鍵,可以使一個鍵的mem服務器落點變成是動態選擇(一個服務器down掉然後選擇crc32(key)後大於這個服務器的落點....)
添加虛擬節點,虛擬節點其實還是原來那幾臺服務器,每個虛擬節點都對應一個真實的服務器,起到分散節點的作用
原理如:關鍵點 hash環的理解和構建。
代碼如下:libraries/MemCluster.php
<?php
/**
*/
//一致性hash
// 功能 添加節點; ;根據用戶數據key 獲取應該使用那臺node
class MemCluster
{
protected $nodes = array();
protected $position = array();
protected $virtualNum=32; //每個節點有32個虛擬節點;具體數量也可以 16 ,8等
public function hash($str){
//將字符串轉成32位符號整數
return sprintf("%u", crc32($str));
}
//查找key 落到哪個節點上
public function findNode($key){
$point = $this->hash($key);
//先取圓環上最小的一個節點
//$key 哈希後比最大的節點都大就放到第一個節點
$node = current($this->position);
//下面這個查找可以 後期優化爲二分查找法。
foreach($this->position as $k=>$v){
if($point <= $k){
$node = $v;
break;
}
}
//復位數組指針
reset($this->position);
return $node;
}
public function addNode($node){
if(isset($this->nodes[$node])){
return;
}
for($i=0; $i<$this->virtualNum; $i++){
$pos = $this->hash($node.'-'.$i);
$this->position[$pos] = $node;
//方便刪除對應的虛擬節點
$this->nodes[$node][] = $pos;
}
$this->sortPos();
}
public function delNode($node){
if(!isset($this->nodes[$node])){
return;
}
//刪除對應的虛擬節點
foreach($this->nodes[$node] as $k){
unset($this->position[$k]);
}
unset($this->nodes[$node]);
}
protected function sortPos(){
//正常比較單元,不改變類型
ksort($this->position, SORT_REGULAR);
}
}
測試代碼 如下:contoller/Mem.php
public function test(){
$this->load->library('memcluster');
$memServerArr = array('192.168.0.1:6666', '192.168.0.2:8888', '192.168.0.3:9999');
foreach ($memServerArr as $mem){
$this->memcluster->addNode($mem);
}
$key = "goods:1688";
$memNode = $this->memcluster->findNode($key);
echo $memNode,"<br/>";
$key = "goods:1689";
$memNode = $this->memcluster->findNode($key);
echo $memNode,"<br/>";
$key = "goods:1670";
$memNode = $this->memcluster->findNode($key);
echo $memNode,"<br/>";
$key = "goods:1671";
$memNode = $this->memcluster->findNode($key);
echo $memNode,"<br/>";
$key = "goods:1672";
$memNode = $this->memcluster->findNode($key);
echo $memNode,"<br/>";
$key = "goods:1673";
$memNode = $this->memcluster->findNode($key);
echo $memNode,"<br/>";
$key = "order:1673";
$memNode = $this->memcluster->findNode($key);
echo $memNode,"<br/>";
$key = "order:1674";
$memNode = $this->memcluster->findNode($key);
echo $memNode,"<br/>";
$key = "order:1675";
$memNode = $this->memcluster->findNode($key);
echo $memNode,"<br/>";
$key = "post:1675";
$memNode = $this->memcluster->findNode($key);
echo $memNode,"<br/>";
}