仅仅把 Memcached 服务器集群地址通过一致性哈希转映射在圆环上,可能会出现数据不能均匀地分配给各台 Memcached 服务器。

解决方案是引入虚拟节点,就是把每个映射在圆环上的服务器地址(物理节点)转变成更多的(注:关于虚拟节点的个数参考)虚拟节点。

修改 Memcached 笔记与总结(6)PHP 实现 Memcached 的一致性哈希分布算法 中的代码:

类 consistentHash 增加私有的成员属性:$position,以键值形式保存所有虚拟节点的哈希值(键)和对应的服务器(值)的一维数组

结构如下:

array(
1589449412 => '192.168.1.1'
2566189294 => '192.168.1.1'
4025729144 => '192.168.1.2'
2135743977 => '192.168.1.2'
139193727 => '192.168.1.3'
1522140696 => '192.168.1.3'
)

私有成员属性 $serverList 修改为 以二维数组保存服务器列表和每一个服务器下虚拟节点的哈希值,结构如下:

array(
'192.168.1.1' => array(
0 => 1589449412,
1 => 700064338
),
'192.168.1.2' => array(
0 => 1559997597,
1 => 737975307
)
)

私有成员属性 isSorted 修改为 记录虚拟节点哈希值列表是否已经排列过序

addServer 方法的实现:

    public function addServer($server, $nodesNum = 25){

        if (isset($this->serverList[$server])) {
return;
} //增加虚拟节点,默认每个物理节点变成25个虚拟节点
for($i = 0; $i < $nodesNum; $i++){
$hash = $this->_hash($server.'-'.$i);//计算虚拟节点的Hash值
$this->position[$hash] = $server;
$this->serverList[$server][] = $hash;
} //此时虚拟节点表发生了变化,因此标识为FALSE
$this->isSorted = FALSE;
return TRUE;
}

removeServer 方法的实现:

    public function removeServer($server){

        if (!isset($this->serverList[$server])) {
return;
} //循环position数组,如果要删除的服务器的值等于position数组某个元素的值,则删除该元素
foreach($this->position as $k=>$v){
if($server == $v){
unset($this->position[$k]);
}
} unset($this->serverList[$server]); $this->isSorted = FALSE;
return TRUE;
}

lookup 方法的实现:

    public function lookup($key){
//计算出服务器的Hash值
$hash = $this->_hash($key); //判断服务器列表是否排过序
if (!$this->isSorted) {
//倒序排列(把虚拟节点列表转换成逆时针圆环)
krsort($this->position, SORT_NUMERIC);
$this->isSorted = TRUE;
} //遍历虚拟节点列表,找到合适的服务器并返回
foreach($this->position as $server_hash=> $server){
if ($hash >= $server_hash) return $server;
}
return end($this->position);
}

完整代码:

<?php
//把字符串转换为整数
interface hash{
public function _hash($str);
} interface distribute{
//在当前的服务器列表中找到合适的服务器存放数据
public function lookup($key); //添加一个服务器到服务器列表中
public function addServer($server); //从服务器列表中删除一个服务器
public function removeServer($server);
} class consistentHash implements hash, distribute{ private $serverList = array();//以二维数组保存服务器列表和每一个服务器下虚拟节点的哈希值
private $position = array();//以键值形式保存所有虚拟节点的哈希值(键)和对应的服务器(值)的一维数组
private $isSorted = FALSE; //记录虚拟节点哈希值列表是否已经排列过序 public function _hash($str){
return sprintf('%u', crc32($str));//把字符串转成32为无符号整数
} public function lookup($key){
//计算出服务器的Hash值
$hash = $this->_hash($key); //判断服务器列表是否排过序
if (!$this->isSorted) {
//倒序排列(把虚拟节点列表转换成逆时针圆环)
krsort($this->position, SORT_NUMERIC);
$this->isSorted = TRUE;
} //遍历虚拟节点列表,找到合适的服务器并返回
foreach($this->position as $server_hash=> $server){
if ($hash >= $server_hash) return $server;
}
return end($this->position);
} public function addServer($server, $nodesNum = 25){ if (isset($this->serverList[$server])) {
return;
} //增加虚拟节点,默认每个物理节点变成25个虚拟节点
for($i = 0; $i < $nodesNum; $i++){
$hash = $this->_hash($server.'-'.$i);//计算虚拟节点的Hash值
$this->position[$hash] = $server;
$this->serverList[$server][] = $hash;
} //此时虚拟节点列表发生了变化,因此标识为FALSE
$this->isSorted = FALSE;
return TRUE;
} public function removeServer($server){ if (!isset($this->serverList[$server])) {
return;
} //循环position数组,如果要删除的服务器的值等于position数组某个元素的值,则删除该元素
foreach($this->position as $k=>$v){
if($server == $v){
unset($this->position[$k]);
}
} unset($this->serverList[$server]); $this->isSorted = FALSE;
return TRUE;
}
} $hashserver = new consistentHash(); $hashserver->addServer('192.168.1.1');
$hashserver->addServer('192.168.1.2');
$hashserver->addServer('192.168.1.3');
$hashserver->addServer('192.168.1.4');
$hashserver->addServer('192.168.1.5'); echo 'save key1 on server:',$hashserver->lookup('key1'),'<br />';
echo 'save key2 on server:',$hashserver->lookup('key2'),'<br /><br />'; $hashserver->removeServer('192.168.1.2');
echo 'save key1 on server:',$hashserver->lookup('key1'),'<br />';
echo 'save key2 on server:',$hashserver->lookup('key2'),'<br /><br />'; $hashserver->addServer('192.168.1.6');
echo 'save key1 on server:',$hashserver->lookup('key1'),'<br />';
echo 'save key2 on server:',$hashserver->lookup('key2'),'<br /><br />';

输出:

save key1 on server:192.168.1.2
save key2 on server:192.168.1.1 save key1 on server:192.168.1.3
save key2 on server:192.168.1.1 save key1 on server:192.168.1.6
save key2 on server:192.168.1.1

参考:

Memcached中一致性哈希(Consistent Hashing)的运用

memcached 之 哈希一致性 和 虚拟节点 分析

Memcached 笔记与总结(7)增加虚拟节点的更多相关文章

  1. memcached学习——分布式算法(Consistant hash + 虚拟节点)(三)

    1.取余算法 优点:数据分布均匀缺点:当服务器动态的添加.删除节点或者某台server down掉,会导致命中率超大幅度下降,甚至导致服务不可用 2.Consistant Hash算法:一致性哈希算法 ...

  2. Memcached 笔记与总结(8)Memcached 的普通哈希分布算法和一致性哈希分布算法命中率对比

    准备工作: ① 配置文件 config.php ② 封装 Memcached 类 hash.class.php,包含普通哈希算法(取模)和一致性哈希算法 ③ 初始化 Memcached 节点信息 in ...

  3. Memcached笔记之分布式算法

    1.根据余数进行分散:离散度高,但是增加或者移除服务器的时候,缓存充足的代价非常大.添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,从而音像缓存的命中率. 2.Consistent ...

  4. Hadoop学习笔记—13.分布式集群中节点的动态添加与下架

    开篇:在本笔记系列的第一篇中,我们介绍了如何搭建伪分布与分布模式的Hadoop集群.现在,我们来了解一下在一个Hadoop分布式集群中,如何动态(不关机且正在运行的情况下)地添加一个Hadoop节点与 ...

  5. Memcached笔记——(四)应对高并发攻击【转】

    http://snowolf.iteye.com/blog/1677495 近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源.他们的最 ...

  6. 快速增加controller节点

    # controller1节点部署成功后,再添加controller节点,复制配置文件并修改即可openstack pike 部署 目录汇总 http://www.cnblogs.com/elvi/p ...

  7. ACK容器服务虚拟节点使用阿里云日志服务来收集业务容器日志

    按照这篇博文的介绍,可以在ACK集群上通过Helm的方式部署虚拟节点,提升集群的弹性能力.现在,通过虚拟节点部署的ECI弹性容器实例也支持将stdout输出.日志文件同步到阿里云日志服务(SLS)进行 ...

  8. Memcached笔记——(四)应对高并发攻击

    近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源.他们的最好成绩,1秒钟可以并发6次,赶在Database入库前,Cache进行Mis ...

  9. Memcached笔记——(二)XMemcached&Spring集成

    今天研究Memcached的Java的Client,使用XMemcached 1.3.5,做个简单的测试,并介绍如何与Spring集成. 相关链接: Memcached笔记--(一)安装&常规 ...

随机推荐

  1. 短信猫 TIdTCPServer TIdTCPClient

    短信猫 服务端: IdTCPServer1: TIdTCPServer; IdAntiFreeze1: TIdAntiFreeze; unit UnitSever; interface uses Wi ...

  2. 【转】Python yield 使用浅析

    转载地址: www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/ Python yield 使用浅析 初学 Python 的开发者经 ...

  3. HDU4080 Stammering Aliens(二分 + 后缀数组)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4080 Description Dr. Ellie Arroway has establish ...

  4. POJ3613 Cow Relays(矩阵快速幂)

    题目大概要求从起点到终点恰好经过k条边的最短路. 离散数学告诉我们邻接矩阵的k次幂就能得出恰好经过k条路的信息,比如POJ2778. 这题也一样,矩阵的幂运算定义成min,而min满足结合律,所以可以 ...

  5. BZOJ4684 : Company Organization

    二分答案,转化为判定问题. 建立有向图,$a->b$连边表示$a$是$b$的子集,至此可以处理掉$1$和$2$. 对于$5$,则往对应点的集合塞一个元素,即可满足$5$. 首先求出强连通分量进行 ...

  6. [NOIP2015]运输计划 D2 T3 LCA+二分答案+差分数组

    [NOIP2015]运输计划 D2 T3 Description 公元2044年,人类进入了宇宙纪元. L国有n个星球,还有n-1条双向航道,每条航道建立在两个星球之间,这n-1条航道连通了L国的所有 ...

  7. [转]Hive:简单查询不启用Mapreduce job而启用Fetch task

    转自:http://www.iteblog.com/archives/831 如果你想查询某个表的某一列,Hive默认是会启用MapReduce Job来完成这个任务,如下: hive> SEL ...

  8. 20145304 Java第八周学习报告

    20145304<Java程序设计>第八周学习总结 教材学习内容总结 NIO NIO使用频道来衔接数据节点,在处理数据时,NIO可以让你设定缓冲区容量,在缓冲区中对感兴趣的数据区块进行标记 ...

  9. [Leetcode] Word BreakII

    Question: Given a string s and a dictionary of words dict, add spaces in s to construct a sentence w ...

  10. Codeforces #Round 376 部分题解

    A: 题目传送门:http://codeforces.com/problemset/problem/731/A 直接根据题意模拟即可 #include "bits/stdc++.h" ...