您的位置:首页 > 数据库 > Redis

一致性hash算法-php-redis版本

2015-07-09 23:10 549 查看
<?php
//抄过来的代码,改了一点点,
//实际来说,效率偏低,命中还算均匀

class RedisHash {

private $_node = array();
private $_nodeData = array();
private $_keyNode = 0;
private $_redis = null;
public  $nodeCounter=[];

//每个物理服务器生成虚拟节点个数 [注:节点数越多,cache分布的均匀性越好,
//同时set get操作时,也更耗资源,10台物理服务器,采用200较为合理]
private $_virtualNodeNum = 100;

private function __construct() {

$config = [
'127.0.0.1:6370',
'127.0.0.1:6371',
'127.0.0.1:6372',
'127.0.0.1:6373',
'127.0.0.1:6374',
'127.0.0.1:6375',
'127.0.0.1:6376',
'127.0.0.1:6377',
'127.0.0.1:6378',
'127.0.0.1:6379',
];
if (!$config) throw new Exception('Cache config NULL');

foreach ($config as $key => $value) {
for ($i = 0; $i < $this->_virtualNodeNum; $i++) {
$this->_node[sprintf("%u", crc32($value . '_' . $i))] = $value . '_' . $i;
}
}
ksort($this->_node);
}

private function __clone(){}

static public function getInstance() {
static $redisObj = null;
if (!is_object($redisObj)) {
$redisObj = new self();
}
return $redisObj;
}

public function getRedis($key) {
$this->_nodeData = array_keys($this->_node);
$this->_keyNode = sprintf("%u", crc32($key));
$nodeKey = $this->_findServerNode();
//如果超出环,从头再用二分法查找一个最近的,然后环的头尾做判断,取最接近的节点
if ($this->_keyNode > end($this->_nodeData)) {
$this->_keyNode -= end($this->_nodeData);
$nodeKey2 = $this->_findServerNode();
if (abs($nodeKey2 - $this->_keyNode) < abs($nodeKey - $this->_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->_redis[$config])) {
$this->_redis[$config] = new \Redis;
list($host, $port) = explode(':', $config);
$this->_redis[$config]->connect($host, $port);
}

$this->nodeCounter[$config] ++;

return $this->_redis[$config];
}

private function _findServerNode($m = 0, $b = 0) {
$total = count($this->_nodeData);
if ($total != 0 && $b == 0) $b = $total - 1;
if ($m < $b){
$avg = (int)(($m+$b) / 2);
if ($this->_nodeData[$avg] == $this->_keyNode) {
return $this->_nodeData[$avg];
}elseif ($this->_keyNode < $this->_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) < abs($this->_nodeData[$m] - $this->_keyNode))  return $this->_nodeData[$b];
else return $this->_nodeData[$m];
}

public function set($key, $value, $expire = 0) {
return $this->getRedis($key)->set($key, $value,$expire);
}

public function get($key) {
return $this->getRedis($key)->get($key);
}

public function delete($key) {
return $this->getRedis($key)->delete($key);
}

}

$time_start = microtime(true);
$redis = RedisHash::getInstance();
for($i=0;$i<10000;$i++) {
$b = $redis->set('m_key'.$i, $i);
}
print_r($redis->nodeCounter);
echo  microtime( true ) - $time_start ;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息