一致性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);
时不我待,不负韶华!立刻行动!不吃学习的苦就会吃生活的苦!