关闭

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

标签: phprediscache一致性hash命中
232人阅读 评论(0) 收藏 举报
分类:
<?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 ;   



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:5943次
    • 积分:139
    • 等级:
    • 排名:千里之外
    • 原创:8篇
    • 转载:3篇
    • 译文:0篇
    • 评论:0条
    文章分类