Memcached 笔记与总结(7)增加虚拟节点
仅仅把 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 笔记与总结(7)增加虚拟节点的更多相关文章
- memcached学习——分布式算法(Consistant hash + 虚拟节点)(三)
1.取余算法 优点:数据分布均匀缺点:当服务器动态的添加.删除节点或者某台server down掉,会导致命中率超大幅度下降,甚至导致服务不可用 2.Consistant Hash算法:一致性哈希算法 ...
- Memcached 笔记与总结(8)Memcached 的普通哈希分布算法和一致性哈希分布算法命中率对比
准备工作: ① 配置文件 config.php ② 封装 Memcached 类 hash.class.php,包含普通哈希算法(取模)和一致性哈希算法 ③ 初始化 Memcached 节点信息 in ...
- Memcached笔记之分布式算法
1.根据余数进行分散:离散度高,但是增加或者移除服务器的时候,缓存充足的代价非常大.添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,从而音像缓存的命中率. 2.Consistent ...
- Hadoop学习笔记—13.分布式集群中节点的动态添加与下架
开篇:在本笔记系列的第一篇中,我们介绍了如何搭建伪分布与分布模式的Hadoop集群.现在,我们来了解一下在一个Hadoop分布式集群中,如何动态(不关机且正在运行的情况下)地添加一个Hadoop节点与 ...
- Memcached笔记——(四)应对高并发攻击【转】
http://snowolf.iteye.com/blog/1677495 近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源.他们的最 ...
- 快速增加controller节点
# controller1节点部署成功后,再添加controller节点,复制配置文件并修改即可openstack pike 部署 目录汇总 http://www.cnblogs.com/elvi/p ...
- ACK容器服务虚拟节点使用阿里云日志服务来收集业务容器日志
按照这篇博文的介绍,可以在ACK集群上通过Helm的方式部署虚拟节点,提升集群的弹性能力.现在,通过虚拟节点部署的ECI弹性容器实例也支持将stdout输出.日志文件同步到阿里云日志服务(SLS)进行 ...
- Memcached笔记——(四)应对高并发攻击
近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源.他们的最好成绩,1秒钟可以并发6次,赶在Database入库前,Cache进行Mis ...
- Memcached笔记——(二)XMemcached&Spring集成
今天研究Memcached的Java的Client,使用XMemcached 1.3.5,做个简单的测试,并介绍如何与Spring集成. 相关链接: Memcached笔记--(一)安装&常规 ...
随机推荐
- PHP 设置代码执行时间
<?php ini_set('max_execution_time', '0'); set_time_limit(0); ?>
- Codeforce 493c
H - Vasya and Basketball Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & ...
- unity 常用函数
GameObject.FindGameObjectByTag(); anim.SetFloat("speed",Mathf.Abs(h)); Physics2D.lineCast2 ...
- BZOJ4665 : 小w的喜糖
考虑枚举哪些人一定不合法,那么方案数可以通过简单的排列组合算出. 于是设$f[i][j]$表示前$i$种糖果,一共有$j$个人一定不合法的方案数,但是这样并不能保证其他人一定合法,所以需要进行容斥. ...
- 创建第一个Hiberntae工程
一.前言 很久之前已经对Hibernate有所了解,在项目中进行过简单的应用,基本了解hibernate的简单应用,没有深入的了解,来Shine公司快三个月了,公司的ORM框架就是用Hiberante ...
- viewpager 与 radiogroup 联动时的位置问题
public void onPageSelected(int position) {} 方法中得到radiobutton时,最好通过(RadioButton) this.radioGroup.find ...
- float使内联支持宽高
float使内联元素支持了宽高,可以设置宽高属性:float消除内联元素的空格:
- 炫酷的jquery瀑布流
最近做了一个瀑布流效果,思路很简单 首先计算屏幕一行可以放多少个图片,然后在第二行开始,计算每一列的高度并取出最小值,将新图片加载在最小列高度下,如此循环,并且设定一个条件,当滑动到一定距离后,开始重 ...
- 【BZOJ】1513: [POI2006]Tet-Tetris 3D
题意 给\(n(1 \le n \le 20000)\)个立方体\((x, y, z)\),依次落下.求所有立方体落下完了以后最高的高度. 分析 平面求最大值,平面更新最大值. 题解 二维线段树走起, ...
- 【HDU】4405 Aeroplane chess
http://acm.hdu.edu.cn/showproblem.php?pid=4405 题意:每次可以走1~6格,初始化在第0格,走到>=n的格子就结束.还有m个传送门,表示可以从X[i] ...