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的链接,我就是看懂,然后自己写了下,不喜勿喷。