php 一致性hash,【转载】memcache分布式 [一致性hash算法] 的php实现
最近在看一些分布式方面的文章,所以就用php實(shí)現(xiàn)一致性hash來練練手,以前一般用的是最原始的hash取模做分布式,當(dāng)生產(chǎn)過程中添加或刪除一臺(tái)memcache都會(huì)造成數(shù)據(jù)的全部失效,一致性hash就是為了解決這個(gè)問題,把失效數(shù)據(jù)降到最低,相關(guān)資料可以google一下!
php實(shí)現(xiàn)效率有一定的缺失,如果要高效率,還是寫擴(kuò)展比較好
經(jīng)測(cè)試,5個(gè)memcache,每個(gè)memcache生成100個(gè)虛擬節(jié)點(diǎn),set加get1000次,與單個(gè)memcache直接set加get慢5倍,所以效率一般,有待優(yōu)化!
實(shí)現(xiàn)過程:
memcache的配置 ip+端口+虛擬節(jié)點(diǎn)序列號(hào) 做hash,使用的是crc32,形成一個(gè)閉環(huán)。
對(duì)要操作的key進(jìn)行crc32
二分法在虛擬節(jié)點(diǎn)環(huán)中查找最近的一個(gè)虛擬節(jié)點(diǎn)
從虛擬節(jié)點(diǎn)中提取真實(shí)的memcache ip和端口,做單例連接
/**
*?一致性哈希memcache分布式,采用的是虛擬節(jié)點(diǎn)的方式解決分布均勻性問題,查找節(jié)點(diǎn)采用二分法快速查找
*?the?last?known?user?to?change?this?file?in?the?repository??
*?@author?nash.xiong?
*?@copyright?Copyright???2003-2012?phpd.cn
*?@license
*/
class?memcacheHashMap?{
private?$_node?=?array();
private?$_nodeData?=?array();
private?$_keyNode?=?0;
private?$_memcache?=?null;
//每個(gè)物理服務(wù)器生成虛擬節(jié)點(diǎn)個(gè)數(shù)?[注:節(jié)點(diǎn)數(shù)越多,cache分布的均勻性越好,同時(shí)set?get操作時(shí),也更耗資源,10臺(tái)物理服務(wù)器,采用200較為合理]
private?$_virtualNodeNum?=?200;
private?function?__construct()?{
/*?放入配置文件?*/
$config?=?array(
'127.0.0.1:11211',
'127.0.0.1:11212',
'127.0.0.1:11213',
'127.0.0.1:11214',
'127.0.0.1:11215'
);
if?(!$config)?throw?new?Exception('Cache?config?NULL');
foreach?($config?as?$key?=>?$value)?{
for?($i?=?0;?$i?_virtualNodeNum;?$i++)?{
$this->_node[sprintf("%u",?crc32($value?.?'_'?.?$i))]?=?$value?.?'_'?.?$i;
}
}
ksort($this->_node);
}
private?function?__clone(){}
/**
*?單例,保證只有一個(gè)實(shí)例
*/
static?public?function?getInstance()?{
static?$memcacheObj?=?null;
if?(!is_object($memcacheObj))?{
$memcacheObj?=?new?self();
}
return?$memcacheObj;
}
/**
*?根據(jù)key做一致性hash后連接到一臺(tái)物理memcache服務(wù)器
*?@param?string?$key
*/
private?function?_connectMemcache($key)?{
$this->_nodeData?=?array_keys($this->_node);
$this->_keyNode?=?sprintf("%u",?crc32($key));
$nodeKey?=?$this->_findServerNode();
//如果超出環(huán),從頭再用二分法查找一個(gè)最近的,然后環(huán)的頭尾做判斷,取最接近的節(jié)點(diǎn)
if?($this->_keyNode?>?end($this->_nodeData))?{
$this->_keyNode?-=?end($this->_nodeData);
$nodeKey2?=?$this->_findServerNode();
if?(abs($nodeKey2?-?$this->_keyNode)?_keyNode))??$nodeKey?=?$nodeKey2;
}
var_dump($this->_node[$nodeKey]);
list($config,?$num)?=?explode('_',?$this->_node[$nodeKey]);
if?(!$config)?throw?new?Exception('Cache?config?Error');
if?(!isset($this->_memcache[$config]))?{
$this->_memcache[$config]?=?new?Memcache;
list($host,?$port)?=?explode(':',?$config);
$this->_memcache[$config]->connect($host,?$port);
}
return?$this->_memcache[$config];
}
/**
*?采用二分法從虛擬memcache節(jié)點(diǎn)中查找最近的節(jié)點(diǎn)
*?@param?unknown_type?$m
*?@param?unknown_type?$b
*/
private?function?_findServerNode($m?=?0,?$b?=?0)?{
$total?=?count($this->_nodeData);
if?($total?!=?0?&&?$b?==?0)?$b?=?$total?-?1;
if?($m?
$avg?=?intval(($m+$b)?/?2);
if?($this->_nodeData[$avg]?==?$this->_keyNode)?return?$this->_nodeData[$avg];
elseif?($this->_keyNode?_nodeData[$avg]?&&?($avg-1?>=?0))?return?$this->_findServerNode($m,?$avg-1);
else?return?$this->_findServerNode($avg+1,?$b);
}
if?(abs($this->_nodeData[$b]?-?$this->_keyNode)?_nodeData[$m]?-?$this->_keyNode))??return?$this->_nodeData[$b];
else?return?$this->_nodeData[$m];
}
public?function?set($key,?$value,?$expire?=?0)?{
return?$this->_connectMemcache($key)->set($key,?json_encode($value),?0,?$expire);
}
public?function?add($key,?$value,?$expire?=?0)?{
return?$this->_connectMemcache($key)->add($key,?json_encode($value),?0,?$expire);
}
public?function?get($key)?{
return?json_decode($this->_connectMemcache($key)->get($key),?true);
}
public?function?delete($key)?{
return?$this->_connectMemcache($key)->delete($key);
}
}
$runData['BEGIN_TIME']?=?microtime(true);
//測(cè)試一萬次set加get
for($i=0;$i<10000;$i++)?{
$key?=?md5(mt_rand());
$b?=?memcacheHashMap::getInstance()->set($key,?time(),?10);
}
var_dump(number_format(microtime(true)?-?$runData['BEGIN_TIME'],6));
$runData['BEGIN_TIME']?=?microtime(true);?$m=?new?Memcache;
$m->connect('127.0.0.1',?11211);
for($i=0;$i<10000;$i++)?{
$key?=?md5(mt_rand());
$b?=?$m->set($key,?time(),?0,?10);
}
var_dump(number_format(microtime(true)?-?$runData['BEGIN_TIME'],6));
//測(cè)試結(jié)果,采用一致性哈希分布效率比原生單臺(tái)速度相差5倍左右
總結(jié)
以上是生活随笔為你收集整理的php 一致性hash,【转载】memcache分布式 [一致性hash算法] 的php实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java中optionnull_用 op
- 下一篇: php5.6 开二级域名,PHP二级域名