一致性hash

  1 <?php
  2 /**
  3  * 分布式缓存部署方案
  4  * 当有1台cache服务器不能满足我们的需求,我们需要布置多台来做分布式服务器,但是
  5  * 有个问题,怎么确定一个数据应该保存到哪台服务器上呢?
  6  * 有两种方案,第一种普通hash分布,第二种一致性哈希分布
  7  *
  8  * 普通hash分布
  9  * 首先将key处理为一个32位字符串,取前8位,在经过hash计算处理成整数并返回,然后映射到其中一台服务器
 10  * $servers[mhash($key) % 2] 这样得到其中一台服务器的配置,利用这个配置完成分布式部署
 11  * 在服务器数量不发生变化的情况下,普通hash分布可以很好的运作,当服务器的数量发生变化,问题就来了
 12  * 试想,增加一台服务器,同一个key经过hash之后,与服务器取模的结果和没增加之前的结果肯定不一样,这就导致了,之前保存的数据丢失
 13  *
 14  * 一致性哈希算法
 15  * 优点:在分布式的cache缓存中,其中一台宕机,迁移key效率最高
 16  * 将服务器列表进行排序,根据mHash($key) 匹配相邻服务器
 17  */
 18  
 19 /**
 20  * hash算法
 21  * @param string $key
 22  * @return int
 23  */
 24 function mHash($key)
 25 {
 26     $md5 = substr(md5($key), 0, 8);
 27     $seed = 31;
 28     $hash = 0;
 29      
 30     for($i = 0; $i < 8; $i++){
 31         $hash = $hash * $seed + ord($md5{$i});
 32         $i++;
 33     }
 34     return $hash & 0x7FFFFFFF;
 35 }
 36  
 37 class FlexiHash
 38 {
 39     // 服务器列表
 40     private $serverList = array();
 41     // 服务器列表key数组
 42      private $serverKeys = array();
 43     // 是否排序
 44     private $isSorted = false;
 45      
 46     /**
 47      * 添加服务器
 48      * @param string $server
 49      * @return boolean
 50      */
 51     function addServer($server)
 52     {
 53         $hash = mHash($server);
 54         if (!isset($this->serverList[$hash])) {
 55             $this->serverList[$hash] = $server;
 56         }
 57         $this->isSorted = false;
 58         return true;
 59     }
 60      
 61     /**
 62      * 移除服务器
 63      * @param string $server
 64      * @return boolean
 65      */
 66     function removeServer($server)
 67     {
 68         $hash = mHash($server);
 69         if (isset($this->serverList[$hash])) {
 70             unset($this->serverList[$hash]);
 71         }
 72         $this->isSorted = false;
 73         return true;
 74     }
 75      
 76     /**
 77      * 根据$key逆时针查找相邻的服务器
 78      * @param string $key
 79      * @return string
 80      */
 81     function lookup($key)
 82     {
 83         $hash = mHash($key);
 84         // 对服务器列表逆排序
 85         if (!$this->isSorted) {
 86             krsort($this->serverList, SORT_NUMERIC);
 87             $this->isSorted = true;
 88               $this->serverKeys = array_keys($this->serverList);
 89         }
 90         // 查找相邻的数据
 91         foreach ($this->serverList as $pos => $server) {
 92             if ($hash >=  $pos) return $server;
 93         }
 94         // 找不到,返回最后一个
 95         return $this->serverList[$this->serverKeys[count($this->serverList) - 1]];
 96     }
 97 }
 98  
 99 $hserver = new FlexiHash();
100 $hserver->addServer('192.168.1.1');
101 $hserver->addServer('192.168.1.2');
102 $hserver->addServer('192.168.1.3');
103 $hserver->addServer('192.168.1.4');
104 $hserver->addServer('192.168.1.5');
105 $hserver->addServer('192.168.1.6');
106  
107 echo "<pre>";
108 for($i=0; $i < 10000; $i++) {
109   $t = $hserver->lookup('key'.$i);
110   $arr[] = $t;
111 }
112 print_r($arr);

 

posted @ 2015-05-27 10:31  不负韶华668  阅读(209)  评论(0编辑  收藏  举报