当前位置:首页 > PHP教程 > php应用 > 列表

memcache一致性hash的php实现方法

发布:smiling 来源: PHP粉丝网  添加日期:2021-05-15 17:13:23 浏览: 评论:0 

这篇文章主要介绍了memcache一致性hash的php实现方法,实例分析了memcache中hash一致性的实现原理与相关技巧,需要的朋友可以参考下

本文实例讲述了memcache一致性hash的php实现方法。分享给大家供大家参考。具体如下:

最近在看一些分布式方面的文章,所以就用php实现一致性hash来练练手,以前一般用的是最原始的hash取模做 分布式,当生产过程中添加或删除一台memcache都会造成数据的全部失效,一致性hash就是为了解决这个问题,把失效数据降到最低,相关资料可以 google一下!

php实现效率有一定的缺失,如果要高效率,还是写扩展比较好

经测试,5个memcache,每个memcache生成100个虚拟节点,set加get1000次,与单个memcache直接set加get慢5倍,所以效率一般,有待优化!

在阅读本文之前,最好知道二分查找法。

实现过程:

memcache的配置 ip+端口+虚拟节点序列号 做hash,使用的是crc32,形成一个闭环。

对要操作的key进行crc32

二分法在虚拟节点环中查找最近的一个虚拟节点

从虚拟节点中提取真实的memcache ip和端口,做单例连接,代码如下:

  1. <?php 
  2. class memcacheHashMap { 
  3.         private $_node = array(); 
  4.         private $_nodeData = array(); 
  5.         private $_keyNode = 0; 
  6.         private $_memcache = null; 
  7.         //每个物理服务器生成虚拟节点个数 [注:节点数越多,cache分布的均匀性越好,同时set get操作时,也更耗资源,10台物理服务器,采用200较为合理] 
  8.         private $_virtualNodeNum = 200; 
  9.         private function __construct() { 
  10.                 $config = array(//五个memcache服务器 
  11.                                                 '127.0.0.1:11211'
  12.                                                 '127.0.0.1:11212'
  13.                                                 '127.0.0.1:11213'
  14.                                                 '127.0.0.1:11214'
  15.                                                 '127.0.0.1:11215' 
  16.                                         ); 
  17.                 if (!$configthrow new Exception('Cache config NULL'); 
  18.                 foreach ($config as $key => $value) { 
  19.                         for ($i = 0; $i < $this->_virtualNodeNum; $i++) { 
  20.                                 $this->_node[sprintf("%u", crc32($value . '_' . $i))] = $value . '_' . $i;//循环为每个memcache服务器创建200个虚拟节点 
  21.                         } 
  22.                 } 
  23.                 ksort($this->_node);//创建出来的1000个虚拟节点按照键名从小到大排序 
  24.         } 
  25.         //实例化该类 
  26.         static public function getInstance() { 
  27.                 static $memcacheObj = null; 
  28.                 if (!is_object($memcacheObj)) { 
  29.                         $memcacheObj = new self(); 
  30.                 } 
  31.                 return $memcacheObj
  32.         } 
  33.         //根据传来的键查找到对应虚拟节点的位置 
  34.         private function _connectMemcache($key) { 
  35.                 $this->_nodeData = array_keys($this->_node);//所有的虚拟节点的键的数组 
  36.                 $this->_keyNode = sprintf("%u", crc32($key));//算出键的hash值 
  37.                 $nodeKey = $this->_findServerNode();//找出对应的虚拟节点 
  38.                 //如果超出环,从头再用二分法查找一个最近的,然后环的头尾做判断,取最接近的节点 
  39.                 if ($this->_keyNode > end($this->_nodeData)) { 
  40.                         $this->_keyNode -= end($this->_nodeData); 
  41.                         $nodeKey2 = $this->_findServerNode(); 
  42.                         if (abs($nodeKey2 - $this->_keyNode) < abs($nodeKey - $this->_keyNode))  $nodeKey = $nodeKey2
  43.                 } 
  44.                 var_dump($this->_node[$nodeKey]); 
  45.                 list($config$num) = explode('_'$this->_node[$nodeKey]); 
  46.                 if (!$configthrow new Exception('Cache config Error'); 
  47.                 if (!isset($this->_memcache[$config])) { 
  48.                         $this->_memcache[$config] = new Memcache; 
  49.                         list($host$port) = explode(':'$config); 
  50.                         $this->_memcache[$config]->connect($host$port); 
  51.                 } 
  52.                 return $this->_memcache[$config]; 
  53.         } 
  54.         //二分法根据给出的值找出最近的虚拟节点位置 
  55.         private function _findServerNode($m = 0, $b = 0) { 
  56.             $total = count($this->_nodeData); 
  57.             if ($total != 0 && $b == 0) $b = $total - 1; 
  58.             if ($m < $b){ 
  59.                 $avg = intval(($m+$b) / 2); 
  60.                 if ($this->_nodeData[$avg] == $this->_keyNode) return $this->_nodeData[$avg]; 
  61.                 elseif ($this->_keyNode < $this->_nodeData[$avg] && ($avg-1 >= 0)) return $this->_findServerNode($m$avg-1); 
  62.                 else return $this->_findServerNode($avg+1, $b); 
  63.             } 
  64.                 if (abs($this->_nodeData[$b] - $this->_keyNode) < abs($this->_nodeData[$m] - $this->_keyNode))  return $this->_nodeData[$b]; 
  65.                 else return $this->_nodeData[$m]; 
  66.         } 
  67.         public function set($key$value$expire = 0) { 
  68.                 return $this->_connectMemcache($key)->set($key, json_encode($value), 0, $expire); 
  69.         } 
  70.         public function add($key$value$expire = 0) { 
  71.                 return $this->_connectMemcache($key)->add($key, json_encode($value), 0, $expire); 
  72.         } 
  73.         public function get($key) { 
  74.                 return json_decode($this->_connectMemcache($key)->get($key), true); 
  75.         } 
  76.         public function delete($key) { 
  77.                 return $this->_connectMemcache($key)->delete($key); 
  78.         } 
  79. $runData['BEGIN_TIME'] = microtime(true); 
  80. //测试一万次set加get 
  81. for($i=0;$i<10000;$i++) { 
  82.         $key = md5(mt_rand()); 
  83.         $b = memcacheHashMap::getInstance()->set($key, time(), 10); 
  84. var_dump(number_format(microtime(true) - $runData['BEGIN_TIME'],6)); 
  85. $runData['BEGIN_TIME'] = microtime(true); $mnew Memcache; 
  86. $m->connect('127.0.0.1', 11211); 
  87. for($i=0;$i<10000;$i++) { 
  88.         $key = md5(mt_rand()); 
  89.         $b = $m->set($key, time(), 0, 10); 
  90. var_dump(number_format(microtime(true) - $runData['BEGIN_TIME'],6)); 
  91. ?>

Tags: memcache hash

分享到: