memcache一致性hash的php实现方法
memcache一致性hash的php实现方法
开元中国2015 发表于3年前
memcache一致性hash的php实现方法
  • 发表于 3年前
  • 阅读 82
  • 收藏 8
  • 点赞 0
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

memcache一致性hash的php实现方法

本文实例讲述了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和端口,做单例连接

[php] view plaincopy

  1. <?php  

  2.   

  3. class memcacheHashMap {  

  4.   

  5.         private $_node = array();  

  6.   

  7.         private $_nodeData = array();  

  8.   

  9.         private $_keyNode = 0;  

  10.   

  11.         private $_memcache = null;  

  12.   

  13.         //每个物理服务器生成虚拟节点个数 [注:节点数越多,cache分布的均匀性越好,同时set get操作时,也更耗资源,10台物理服务器,采用200较为合理]  

  14.   

  15.         private $_virtualNodeNum = 200;  

  16.   

  17.         private function __construct() {  

  18.   

  19.                 $config = array(//五个memcache服务器  

  20.   

  21.                                                 '127.0.0.1:11211',  

  22.   

  23.                                                 '127.0.0.1:11212',  

  24.   

  25.                                                 '127.0.0.1:11213',  

  26.   

  27.                                                 '127.0.0.1:11214',  

  28.   

  29.                                                 '127.0.0.1:11215'  

  30.   

  31.                                         );  

  32.   

  33.                 if (!$configthrow new Exception('Cache config NULL');  

  34.   

  35.                 foreach ($config as $key => $value) {  

  36.   

  37.                         for ($i = 0; $i < $this->_virtualNodeNum; $i++) {  

  38.   

  39.                                 $this->_node[sprintf("%u", crc32($value . '_' . $i))] = $value . '_' . $i;//循环为每个memcache服务器创建200个虚拟节点  

  40.   

  41.                         }  

  42.   

  43.                 }  

  44.   

  45.                 ksort($this->_node);//创建出来的1000个虚拟节点按照键名从小到大排序  

  46.   

  47.         }  

  48.   

  49.         //实例化该类  

  50.   

  51.         static public function getInstance() {  

  52.   

  53.                 static $memcacheObj = null;  

  54.   

  55.                 if (!is_object($memcacheObj)) {  

  56.   

  57.                         $memcacheObj = new self();  

  58.   

  59.                 }  

  60.   

  61.                 return $memcacheObj;  

  62.   

  63.         }  

  64.   

  65.         //根据传来的键查找到对应虚拟节点的位置  

  66.   

  67.         private function _connectMemcache($key) {  

  68.   

  69.                 $this->_nodeData = array_keys($this->_node);//所有的虚拟节点的键的数组  

  70.   

  71.                 $this->_keyNode = sprintf("%u", crc32($key));//算出键的hash值  

  72.   

  73.                 $nodeKey = $this->_findServerNode();//找出对应的虚拟节点  

  74.   

  75.                 //如果超出环,从头再用二分法查找一个最近的,然后环的头尾做判断,取最接近的节点  

  76.   

  77.                 if ($this->_keyNode > end($this->_nodeData)) {  

  78.   

  79.                         $this->_keyNode -= end($this->_nodeData);  

  80.   

  81.                         $nodeKey2 = $this->_findServerNode();  

  82.   

  83.                         if (abs($nodeKey2 - $this->_keyNode) < abs($nodeKey - $this->_keyNode))  $nodeKey = $nodeKey2;  

  84.   

  85.                 }  

  86.   

  87.                 var_dump($this->_node[$nodeKey]);  

  88.   

  89.                 list($config$num) = explode('_'$this->_node[$nodeKey]);  

  90.   

  91.                 if (!$configthrow new Exception('Cache config Error');  

  92.   

  93.                 if (!isset($this->_memcache[$config])) {  

  94.   

  95.                         $this->_memcache[$config] = new Memcache;  

  96.   

  97.                         list($host$port) = explode(':'$config);  

  98.   

  99.                         $this->_memcache[$config]->connect($host$port);  

  100.   

  101.                 }  

  102.   

  103.                 return $this->_memcache[$config];  

  104.   

  105.         }  

  106.   

  107.         //二分法根据给出的值找出最近的虚拟节点位置  

  108.   

  109.         private function _findServerNode($m = 0, $b = 0) {  

  110.   

  111.             $total = count($this->_nodeData);  

  112.   

  113.             if ($total != 0 && $b == 0) $b = $total - 1;  

  114.   

  115.             if ($m < $b){  

  116.   

  117.                 $avg = intval(($m+$b) / 2);  

  118.   

  119.                 if ($this->_nodeData[$avg] == $this->_keyNode) return $this->_nodeData[$avg];  

  120.   

  121.                 elseif ($this->_keyNode < $this->_nodeData[$avg] && ($avg-1 >= 0)) return $this->_findServerNode($m$avg-1);  

  122.   

  123.                 else return $this->_findServerNode($avg+1, $b);  

  124.   

  125.             }  

  126.   

  127.                 if (abs($this->_nodeData[$b] - $this->_keyNode) < abs($this->_nodeData[$m] - $this->_keyNode))  return $this->_nodeData[$b];  

  128.   

  129.                 else return $this->_nodeData[$m];  

  130.   

  131.         }  

  132.   

  133.         public function set($key$value$expire = 0) {  

  134.   

  135.                 return $this->_connectMemcache($key)->set($key, json_encode($value), 0, $expire);  

  136.   

  137.         }  

  138.   

  139.         public function add($key$value$expire = 0) {  

  140.   

  141.                 return $this->_connectMemcache($key)->add($key, json_encode($value), 0, $expire);  

  142.   

  143.         }  

  144.   

  145.         public function get($key) {  

  146.   

  147.                 return json_decode($this->_connectMemcache($key)->get($key), true);  

  148.   

  149.         }  

  150.   

  151.         public function delete($key) {  

  152.   

  153.                 return $this->_connectMemcache($key)->delete($key);  

  154.   

  155.         }  

  156.   

  157. }  

  158.   

  159. $runData['BEGIN_TIME'] = microtime(true);  

  160.   

  161. //测试一万次set加get  

  162.   

  163. for($i=0;$i<10000;$i++) {  

  164.   

  165.         $key = md5(mt_rand());  

  166.   

  167.         $b = memcacheHashMap::getInstance()->set($key, time(), 10);  

  168.   

  169. }  

  170.   

  171. var_dump(number_format(microtime(true) - $runData['BEGIN_TIME'],6));  

  172.   

  173. $runData['BEGIN_TIME'] = microtime(true); $mnew Memcache;  

  174.   

  175. $m->connect('127.0.0.1', 11211);  

  176.   

  177. for($i=0;$i<10000;$i++) {  

  178.   

  179.         $key = md5(mt_rand());  

  180.   

  181.         $b = $m->set($key, time(), 0, 10);  

  182.   

  183. }  

  184.   

  185. var_dump(number_format(microtime(true) - $runData['BEGIN_TIME'],6));  

  186.   

  187. ?>  


希望本文所述对大家的php程序设计有所帮助。 

参考来源: 
memcache一致性hash的php实现方法
http://www.lai18.com/content/368526.html


标签: memcache
  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 32
博文 104
码字总数 112959
×
开元中国2015
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: