<?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 ;
一致性hash算法-php-redis版本
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.