一致性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 ;
相关文章推荐
- 一个关于if else容易迷惑的问题
- PHP5.2.*防止Hash冲突拒绝服务攻击的Patch
- 深入理解PHP之匿名函数
- JSP/PHP基于Ajax的分页功能实现
- redis安装问题小结
- 关于PHP通过PDO用中文条件查询MySQL的问题。
- 什么是设计模式
- PHP数据库长连接mysql_pconnect的细节
- Php Installing An Expansion
- Redis偶发连接失败案例实战记录
- 分析Cache 在 Ruby China 里面的应用情况
- Redis中实现查找某个值的范围
- Redis和Memcached的区别详解
- 分割超大Redis数据库例子
- Redis总结笔记(一):安装和常用命令
- Redis sort 排序命令详解
- PHP+Apache在Windows 9x下的安装和配置
- IIS 6 的 PHP 最佳配置方法
- 安装Apache和PHP的一些补充