zoukankan      html  css  js  c++  java
  • 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的链接,我就是看懂,然后自己写了下,不喜勿喷。

           

  • 相关阅读:
    Delphi中创建一个可以改变大小的无边框窗口
    Delphi中让窗口关闭按钮无效的6种方法
    把人笑抽筋的签名
    Delphi中判断窗体最大化和最小化事件
    Delphi中窗体的帮助按钮上执行一个自定义的动作
    无法查询部门收支分析表
    Delphi中去掉限制窗体最小尺寸的Windows约束
    Delphi中在窗体标题栏画自定义文字
    调拨单等单据定位功能没有过滤条件
    Form中对象的引用
  • 原文地址:https://www.cnblogs.com/zafuacm/p/4229380.html
Copyright © 2011-2022 走看看