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

来源:互联网 发布:echo linux 写入文件 编辑:程序博客网 时间:2024/04/30 13:07
<?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
原创粉丝点击