Memcached 一致性hash分布式算法

  1 <?php
  2 
  3     interface HashWay{
  4         public function hash($string);
  5     }
  6 
  7     class Md5HashWay implements HashWay{
  8         public function hash($string){
  9             return md5($string,0,8);
 10         }
 11     }
 12 
 13     class Crc32HashWay implements HashWay{
 14         public function hash($string){
 15             return crc32($string);
 16         }
 17     }
 18 
 19     class HashException extends Exception{
 20 
 21     }
 22 
 23     class ConsistentHash{
 24         //每一台memcached服务器的虚拟节点个数
 25         private $_replicas = 64;
 26         //表示memcached服务器的数量
 27         private $_targetCount = 0;
 28         //虚拟节点散列用到的hash算法
 29         private $_hasher = null;
 30         //一台memcached服务器对应的虚拟节点
 31         private $_targetToPostion = array();
 32         //虚拟节点对应memcached
 33         private $_postionToTarget = array();
 34         //是否排序
 35         private $_postionToTargetSorted = false;
 36 
 37 
 38         //构造函数,确定hasher的方法,已经虚拟节点的个数
 39         public function __construct(HashWay $hash = null,$replicas = null){
 40             $this->_hasher = $hash ? $hash : new Crc32HashWay();
 41             if(!empty($replicas))$this->_replicas = intval($replicas);
 42         }
 43 
 44         //增加一台服务器的操作
 45         public function addTarget($target){
 46             if(isset($this->targetToPostion[$target])){throw new HashException("$target exists");}
 47             
 48             //如果这台服务器没有存在,则给这台服务器去生成虚拟节点
 49             for($i = 0 ; $i < $this->_replicas; $i++){
 50                 $postion = $this->_hasher->hash($target.$i);
 51                 //虚拟节点指向target
 52                 $this->_postionToTarget[$postion] = $target;
 53                 //每一个服务器对应的虚拟节点
 54                 $this->_targetToPostion[$target][] = $postion;
 55             }
 56 
 57             $this->_targetCount++;
 58 
 59             //每次增加memcached服务器过来,虚拟节点都会混乱,必须排序来解决问题
 60             $this->_postToTargetSorted = false;
 61             return $this;
 62         }
 63 
 64         //增加多台memcached服务器
 65         public function addTargets($targets){
 66             if(is_array($targets) && !empty($targets)){
 67                 foreach ($targets as $key => $value) {
 68                     $this->addTarget($value);
 69                 }
 70             }
 71         }
 72 
 73         //删除一台服务器的操作
 74         public function removeTarget($target){
 75             if(!isset($this->_targetToPostion[$target])){throw new HashException("$target not exists");}
 76         
 77             //现在进行删除服务器的操作
 78             foreach ($this->_targetToPostion[$target] as $key => $value) {
 79                 //根据虚拟节点数组,来删除指向target的数组
 80                 if(isset($this->_postionToTarget[$value])){
 81                     unset($this->_postionToTarget[$value]);
 82                 }
 83             }
 84             unset($this->_targetToPostion[$target]);
 85             $this->_targetCount--;
 86             return $this;
 87         }
 88 
 89 
 90         //得到全部的memcached服务器
 91         public function getAllTargets(){
 92             return array_keys($this->_targetToPostion);
 93         }
 94 
 95         //查找存储的服务器
 96         public function lookUp($resource){
 97             $result = $this->lookUpList($resource);
 98             return $this->_postionToTarget[current($result)];
 99         }
100         
101         //lookup函数返回一个环,数组0表示的是顺时针最近的memcached服务器
102         public function lookUpList($resource){
103 
104             if($this->_targetCount == 0){
105                 return array();
106             }
107 
108             //如果只有一个服务器,则返回
109             if($this->_targetCount == 1){
110                 return array_unique(array_values($this->_postionToTarget));
111             }
112             
113 
114             //如果没有找到一个服务器
115             //1对虚拟节点进行排序
116             $this->_sortedPostToTargets();
117 
118 
119             //2对查找的resource进行hash
120             $hashresource = $this->_hasher->hash($resource);
121 
122             //3对虚拟节点查找
123             $flag = false;
124             $result = array();
125 
126             //4优先查找服务器,取得顺时针最近的服务器
127             foreach ($this->_postionToTarget as $key => $value) {
128                 if(!$flag && $key > $hashresource){
129                     $flag = true;
130                 }
131 
132                 if($flag == true && !in_array($key,$result)){
133                     $result[] = $key;
134                 }
135 
136                 if(count($result) == $this->_targetCount){
137                     return $result;
138                 }
139             }
140 
141             //5如果没有在顺时针取得服务器,那就重新再来一遍
142             foreach ($this->_postionToTarget as $key => $value) {
143                 if(!in_array($key,$result)){
144                     $result[] = $key;
145                 }
146 
147                 if(count($result) == $this->_targetCount){
148                     return $result;
149                 }
150             }
151 
152             return $result;
153         }
154 
155         //对虚拟节点进行排序
156         private function _sortedPostToTargets(){
157             if(!$this->_postionToTargetSorted){
158                 ksort($this->_postionToTarget,SORT_REGULAR);
159                 $this->_postionToTargetSorted = true;
160             }
161         }
162     }
163     
164     
165     $a = new ConsistentHash;
166     //添加了两台主机
167     $a->addTarget('192.168.1.1')->addTarget('192.168.1.2')->addTarget('192.168.1.3')->addTarget('192.168.1.4');
168     print_r($a->getAllTargets());
169     
170     echo "<br/>";
171     $result = array();
172     for($i = 0; $i < 100 ; $i++){
173         if(!isset($result[$a->lookUp($i)])){
174             $result[$a->lookUp($i)] = 1;
175         }else{
176             $result[$a->lookUp($i)] ++;
177         }
178     }
179     
180     print_r($result);
181     
182 ?>
Array ( [0] => 192.168.1.1 [1] => 192.168.1.2 [2] => 192.168.1.3 [3] => 192.168.1.4 ) 
Array ( [192.168.1.2] => 13 [192.168.1.1] => 44 [192.168.1.3] => 28 [192.168.1.4] => 15 )

  这边只是简单的代码实现,用于解决分布均衡问题

学习地址:http://blog.csdn.net/cywosp/article/details/23397179

     http://blog.sina.com.cn/s/blog_3fde8252010147j5.html

     好像忘记添加一个链接了,有原代码一致性hash的链接,我就是看懂,然后自己写了下,不喜勿喷。

       

posted on 2015-01-16 17:44  张狂不年轻°  阅读(173)  评论(0编辑  收藏  举报