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
二分法在虚拟节点环中查找最近的一个虚拟节点
从虚拟节点中提取真实的memcacheip和端口,做单例连接
<?php classmemcacheHashMap{ private$_node=array(); private$_nodeData=array(); private$_keyNode=0; private$_memcache=null; //每个物理服务器生成虚拟节点个数[注:节点数越多,cache分布的均匀性越好,同时setget操作时,也更耗资源,10台物理服务器,采用200较为合理] private$_virtualNodeNum=200; privatefunction__construct(){ $config=array(//五个memcache服务器 '127.0.0.1:11211', '127.0.0.1:11212', '127.0.0.1:11213', '127.0.0.1:11214', '127.0.0.1:11215' ); if(!$config)thrownewException('CacheconfigNULL'); foreach($configas$key=>$value){ for($i=0;$i<$this->_virtualNodeNum;$i++){ $this->_node[sprintf("%u",crc32($value.'_'.$i))]=$value.'_'.$i;//循环为每个memcache服务器创建200个虚拟节点 } } ksort($this->_node);//创建出来的1000个虚拟节点按照键名从小到大排序 } //实例化该类 staticpublicfunctiongetInstance(){ static$memcacheObj=null; if(!is_object($memcacheObj)){ $memcacheObj=newself(); } return$memcacheObj; } //根据传来的键查找到对应虚拟节点的位置 privatefunction_connectMemcache($key){ $this->_nodeData=array_keys($this->_node);//所有的虚拟节点的键的数组 $this->_keyNode=sprintf("%u",crc32($key));//算出键的hash值 $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)thrownewException('CacheconfigError'); if(!isset($this->_memcache[$config])){ $this->_memcache[$config]=newMemcache; list($host,$port)=explode(':',$config); $this->_memcache[$config]->connect($host,$port); } return$this->_memcache[$config]; } //二分法根据给出的值找出最近的虚拟节点位置 privatefunction_findServerNode($m=0,$b=0){ $total=count($this->_nodeData); if($total!=0&&$b==0)$b=$total-1; if($m<$b){ $avg=intval(($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); elsereturn$this->_findServerNode($avg+1,$b); } if(abs($this->_nodeData[$b]-$this->_keyNode)<abs($this->_nodeData[$m]-$this->_keyNode)) return$this->_nodeData[$b]; elsereturn$this->_nodeData[$m]; } publicfunctionset($key,$value,$expire=0){ return$this->_connectMemcache($key)->set($key,json_encode($value),0,$expire); } publicfunctionadd($key,$value,$expire=0){ return$this->_connectMemcache($key)->add($key,json_encode($value),0,$expire); } publicfunctionget($key){ returnjson_decode($this->_connectMemcache($key)->get($key),true); } publicfunctiondelete($key){ return$this->_connectMemcache($key)->delete($key); } } $runData['BEGIN_TIME']=microtime(true); //测试一万次set加get for($i=0;$i<10000;$i++){ $key=md5(mt_rand()); $b=memcacheHashMap::getInstance()->set($key,time(),10); } var_dump(number_format(microtime(true)-$runData['BEGIN_TIME'],6)); $runData['BEGIN_TIME']=microtime(true);$m=newMemcache; $m->connect('127.0.0.1',11211); for($i=0;$i<10000;$i++){ $key=md5(mt_rand()); $b=$m->set($key,time(),0,10); } var_dump(number_format(microtime(true)-$runData['BEGIN_TIME'],6)); ?>
希望本文所述对大家的php程序设计有所帮助。