一致性hash算法在memcached中的使用
一、概述
1、我们的memcacheclient(这里我看的spymemcache的源代码)。使用了一致性hash算法ketama进行数据存储节点的选择。与常规的hash算法思路不同。仅仅是对我们要存储数据的key进行hash计算,分配到不同节点存储。一致性hash算法是对我们要存储数据的server进行hash计算,进而确认每一个key的存储位置。
2、常规hash算法的应用以及其弊端
最常规的方式莫过于hash取模的方式。比方集群中可用机器适量为N,那么key值为K的的数据请求非常easy的应该路由到hash(K) mod N相应的机器。
的确,这种结构是简单的,也是有用的。可是在一些快速发展的web系统中,这种解决方式仍有些缺陷。随着系统訪问压力的增长,缓存系统不得不通过添加机器节点的方式提高集群的相应速度和数据承载量。添加机器意味着依照hash取模的方式,在添加机器节点的这一时刻,大量的缓存命不中。缓存数据须要又一次建立,甚至是进行总体的缓存数据迁移,瞬间会给DB带来极高的系统负载。设置导致DBserver宕机。
3、设计分布式cache系统时,一致性hash算法能够帮我们解决哪些问题?
分布式缓存设计核心点:在设计分布式cache系统的时候,我们须要让key的分布均衡。而且在添加cache server后,cache的迁移做到最少。
这里提到的一致性hash算法ketama的做法是:选择详细的机器节点不在仅仅依赖须要缓存数据的key的hash本身了,而是机器节点本身也进行了hash运算。
二、一致性哈希算法情景描写叙述(转载)
1、 hash机器节点
首先求出机器节点的hash值(怎么算机器节点的hash?ip能够作为hash的參数吧。
。当然还有其它的方法了),然后将其分布到0~2^32的一个圆环上(顺时针分布)。例如以下图所看到的:
图一
集群中有机器:A , B, C, D, E五台机器,通过一定的hash算法我们将其分布到如上图所看到的的环上。
2、訪问方式
假设有一个写入缓存的请求。当中Key值为K。计算器hash值Hash(K), Hash(K) 相应于图 – 1环中的某一个点,假设该点相应没有映射到详细的某一个机器节点。那么顺时针查找。直到第一次找到有映射机器的节点。该节点就是确定的目标节点,假设超过了2^32仍然找不到节点,则命中第一个机器节点。比方 Hash(K) 的值介于A~B之间,那么命中的机器节点应该是B节点(如上图 )。
3、添加节点的处理
如上图 – 1,在原有集群的基础上欲添加一台机器F。添加步骤例如以下:
计算机器节点的Hash值,将机器映射到环中的一个节点。例如以下图:
图二
添加机器节点F之后,訪问策略不改变,依旧依照(2)中的方式訪问。此时缓存命不中的情况依旧不可避免,不能命中的数据是hash(K)在添加节点曾经落在C~F之间的数据。虽然依旧存在节点添加带来的命中问题,可是比較传统的 hash取模的方式。一致性hash已经将不命中的数据降到了最低。
Consistent Hashing最大限度地抑制了hash键的又一次分布。另外要取得比較好的负载均衡的效果,往往在server数量比較少的时候须要添加虚拟节点来保证server能均匀的分布在圆环上。
由于使用一般的hash方法,server的映射地点的分布很不均匀。使用虚拟节点的思想。为每一个物理节点(server)在圆上分配100~200个点。
这样就能抑制分布不均匀,最大限度地减小server增减时的缓存又一次分布。
用户数据映射在虚拟节点上,就表示用户数据真正存储位置是在该虚拟节点代表的实际物理server上。
以下有一个图描写叙述了须要为每台物理server添加的虚拟节点。
图三
x轴表示的是须要为每台物理server扩展的虚拟节点倍数(scale)。y轴是实际物理server数。能够看出,当物理server的数量非常小时,须要更大的虚拟节点,反之则须要更少的节点,从图上能够看出,在物理server有10台时。差点儿相同须要为每台server添加100~200个虚拟节点才干达到真正的负载均衡。
三、以spymemcache源代码来演示虚拟节点应用
1、上边描写叙述的一致性Hash算法有个潜在的问题是:
(1)、将节点hash后会不均匀地分布在环上,这样大量key在寻找节点时,会存在key命中各个节点的概率区别较大,无法实现有效的负载均衡。
(2)、如有三个节点Node1,Node2,Node3,分布在环上时三个节点挨的非常近,落在环上的key寻找节点时,大量key顺时针总是分配给Node2,而其他两个节点被找到的概率都会非常小。
2、这样的问题的解决方式能够有:
改善Hash算法,均匀分配各节点到环上;[引文]使用虚拟节点的思想,为每一个物理节点(server)在圆上分配100~200个点。
这样就能抑制分布不均匀,最大限度地减小server增减时的缓存又一次分布。用户数据映射在虚拟节点上。就表示用户数据真正存储位置是在该虚拟节点代表的实际物理server上。
在查看Spy Memcached client时。发现它採用一种称为Ketama的Hash算法。以虚拟节点的思想。解决Memcached的分布式问题。
3、源代码说明
该client採用TreeMap存储全部节点,模拟一个环形的逻辑关系。
在这个环中,节点之前是存在顺序关系的。所以TreeMap的key必须实现Comparator接口。
那节点是如何放入这个环中的呢?
- protected void setKetamaNodes(List<MemcachedNode> nodes) {
- TreeMap<Long, MemcachedNode> newNodeMap = new TreeMap<Long, MemcachedNode>();
- int numReps= config.getNodeRepetitions();
- for(MemcachedNode node : nodes) {
- // Ketama does some special work with md5 where it reuses chunks.
- if(hashAlg == HashAlgorithm.KETAMA_HASH) {
- for(int i=0; i<numReps / 4; i++) {
- byte[] digest=HashAlgorithm.computeMd5(config.getKeyForNode(node, i));
- for(int h=0;h<4;h++) {
- Long k = ((long)(digest[3+h*4]&0xFF) << 24)
- | ((long)(digest[2+h*4]&0xFF) << 16)
- | ((long)(digest[1+h*4]&0xFF) << 8)
- | (digest[h*4]&0xFF);
- newNodeMap.put(k, node);
- getLogger().debug("Adding node %s in position %d", node, k);
- }
- }
- } else {
- for(int i=0; i<numReps; i++) {
- newNodeMap.put(hashAlg.hash(config.getKeyForNode(node, i)), node);
- }
- }
- }
- assert newNodeMap.size() == numReps * nodes.size();
- ketamaNodes = newNodeMap;
protected void setKetamaNodes(List<MemcachedNode> nodes) {
TreeMap<Long, MemcachedNode> newNodeMap = new TreeMap<Long, MemcachedNode>();
int numReps= config.getNodeRepetitions();
for(MemcachedNode node : nodes) {
// Ketama does some special work with md5 where it reuses chunks.
if(hashAlg == HashAlgorithm.KETAMA_HASH) {
for(int i=0; i<numReps / 4; i++) {
byte[] digest=HashAlgorithm.computeMd5(config.getKeyForNode(node, i));
for(int h=0;h<4;h++) {
Long k = ((long)(digest[3+h*4]&0xFF) << 24)
| ((long)(digest[2+h*4]&0xFF) << 16)
| ((long)(digest[1+h*4]&0xFF) << 8)
| (digest[h*4]&0xFF);
newNodeMap.put(k, node);
getLogger().debug("Adding node %s in position %d", node, k);
} }
} else {
for(int i=0; i<numReps; i++) {
newNodeMap.put(hashAlg.hash(config.getKeyForNode(node, i)), node);
}
}
}
assert newNodeMap.size() == numReps * nodes.size();
ketamaNodes = newNodeMap;
上面的流程大概能够这样归纳:四个虚拟结点为一组。以getKeyForNode方法得到这组虚拟节点的name,Md5编码后。每一个虚拟结点相应Md5码16个字节中的4个,组成一个long型数值。做为这个虚拟结点在环中的惟一key。第10行k为什么是Long型的呢?就是由于Long型实现了Comparator接口。
处理完正式结点在环上的分布后,能够開始key在环上寻找节点的游戏了。
对于每一个key还是得完毕上面的步骤:计算出Md5,依据Md5的字节数组,通过Kemata Hash算法得到key在这个环中的位置。
- MemcachedNode getNodeForKey(long hash) {
- final MemcachedNode rv;
- if(!ketamaNodes.containsKey(hash)) {
- // Java 1.6 adds a ceilingKey method, but I'm still stuck in 1.5
- // in a lot of places, so I'm doing this myself.
- SortedMap<Long, MemcachedNode> tailMap=getKetamaNodes().tailMap(hash);
- if(tailMap.isEmpty()) {
- hash=getKetamaNodes().firstKey();
- } else {
- hash=tailMap.firstKey();
- }
- }
- rv=getKetamaNodes().get(hash);
- return rv;
- }
MemcachedNode getNodeForKey(long hash) {
final MemcachedNode rv;
if(!ketamaNodes.containsKey(hash)) {
// Java 1.6 adds a ceilingKey method, but I'm still stuck in 1.5
// in a lot of places, so I'm doing this myself.
SortedMap<Long, MemcachedNode> tailMap=getKetamaNodes().tailMap(hash);
if(tailMap.isEmpty()) {
hash=getKetamaNodes().firstKey();
} else {
hash=tailMap.firstKey();
}
}
rv=getKetamaNodes().get(hash);
return rv;
}
上边代码的实现就是在环上顺时针查找,没找到就去的第一个,然后就知道相应的物理节点了。
四、应用场景分析
1、memcache的add方法:通过一致性hash算法确认当前client相应的cacheserver的hash值以及要存储数据key的hash进行相应,确认cacheserver。获取connection进行数据存储
2、memcache的get方法:通过一致性hash算法确认当前client相应的cacheserver的hash值以及要提取数据的hash值,进而确认存储的cacheserver,获取connection进行数据提取
五、总结
1、一致性hash算法仅仅是帮我们降低cache集群中的机器数量增减的时候,cache的数据能进行最少重建。仅仅要cache集群的server数量有变化。必定产生数据命中的问题
2、对于数据的分布均衡问题。通过虚拟节点的思想来达到均衡分配。当然,我们cache server节点越少就越须要虚拟节点这个方式来均衡负载。
3、我们的cacheclient根本不会维护一个map来记录每一个key存储在哪里。都是通过key的hash和cacheserver(或许ip能够作为參数)的hash计算当前的key应该存储在哪个节点上。
4、当我们的cache节点崩溃了。我们必然丢失部分cache数据。而且要依据活着的cache server和key进行新的一致性匹配计算。
有可能对部分没有丢失的数据也要做重建...
5、至于正常到达数据存储节点,怎样找到key相应的数据,那就是cache server本身的内部算法实现了。此处不做描写叙述。
这里仅仅是针对数据的存储方式以及提取方式进行了流程展示。
转载:http://blog.csdn.net/kongqz/article/details/6695417
一致性hash算法在memcached中的使用的更多相关文章
- 一致性Hash算法在Memcached中的应用
前言 大家应该都知道Memcached要想实现分布式只能在客户端来完成,目前比较流行的是通过一致性hash算法来实现.常规的方法是将server的hash值与server的总台数进行求余,即hash% ...
- (转) 一致性Hash算法在Memcached中的应用
前言 大家应该都知道Memcached要想实现分布式只能在客户端来完成,目前比较流行的是通过一致性hash算法来实现.常规的方法是将 server的hash值与server的总台数进行求余,即hash ...
- 【转载】一致性hash算法释义
http://www.cnblogs.com/haippy/archive/2011/12/10/2282943.html 一致性Hash算法背景 一致性哈希算法在1997年由麻省理工学院的Karge ...
- 一致性Hash算法及使用场景
一.问题产生背景 在使用分布式对数据进行存储时,经常会碰到需要新增节点来满足业务快速增长的需求.然而在新增节点时,如果处理不善会导致所有的数据重新分片,这对于某些系统来说可能是灾难性的. 那 ...
- [转载] 一致性hash算法释义
转载自http://www.cnblogs.com/haippy/archive/2011/12/10/2282943.html 一致性Hash算法背景 一致性哈希算法在1997年由麻省理工学院的Ka ...
- 关于一致性Hash算法
在大型web应用中,缓存可算是当今的一个标准开发配置了.在大规模的缓存应用中,应运而生了分布式缓存系统.分布式缓存系统的基本原理,大家也有所耳闻.key-value如何均匀的分散到集群中?说到此,最常 ...
- 理解一致性Hash算法
简介 一致性哈希算法在1997年由麻省理工学院的Karger等人在解决分布式Cache中提出的,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CAR ...
- OpenStack_Swift源代码分析——Ring基本原理及一致性Hash算法
1.Ring的基本概念 Ring是swfit中最重要的组件.用于记录存储对象与物理位置之间的映射关系,当用户须要对Account.Container.Object操作时,就须要查询相应的Ring文件( ...
- 一致性hash算法及java实现
一致性hash算法是分布式中一个常用且好用的分片算法.或者数据库分库分表算法.现在的互联网服务架构中,为避免单点故障.提升处理效率.横向扩展等原因,分布式系统已经成为了居家旅行必备的部署模式,所以也产 ...
随机推荐
- 牛客网暑期ACM多校训练营(第五场)F take(概率, 递推)
链接: https://www.nowcoder.com/discuss/84119 题意: 给定n个箱子, 每个箱子打开发现钻石的概率P(这里的P要除100), 每个钻石的重量, 有一个人只能持有一 ...
- SAXException Parser configuration problem: namespace reporting is not enabled
问题描述: 用sax的方式组装xml,在tomcat上正常运行,在weblogic12c上报错: SAXException Parser configuration problem: namespac ...
- HTTP/1.1协议支持的8种请求方法
方法 说明 GET 获取资源 POST 传输实体主体 PUT 传输文件 DELETE 删除文件 HEAD 获得报文首部 OPTIONS 询问支持的方法 TRACE 追踪路径 CONNECT 要求用隧道 ...
- HDU-1532 Drainage Ditches,人生第一道网络流!
Drainage Ditches 自己拉的专题里面没有这题,网上找博客学习网络流的时候看到闯亮学长的博客然后看到这个网络流入门题!随手一敲WA了几发看讨论区才发现坑点! 本题采用的是Edmonds-K ...
- Unity3D for iOS初级教程:Part 1/3
转自Unity 3d for ios 这篇文章还可以在这里找到 英语 Learn how to use Unity to make a simple 3D iOS game! 这篇教材是来自教程团队成 ...
- BZOJ 4503 两个串 ——FFT
[题目分析] 定义两个字符之间的距离为 (ai-bi)^2*ai*bi 如果能够匹配,从i到i+m的位置的和一定为0 但这和暴力没有什么区别. 发现把b字符串反过来就可以卷积用FFT了. 听说KMP+ ...
- 【2018.10.20】noip模拟赛Day3 飞行时间
今天模拟赛题目 纯考输入的傻逼题,用$scanf$用到思想僵化的我最终成功被$if$大法爆$0$了(这题只有一组$100$分数据). 输入后面那个$(+1/2)$很难$if$判断,所以我们要判两个字符 ...
- 【loj6191】「美团 CodeM 复赛」配对游戏
题目 显然期望dp. 简单想法: f[i][j]表示前i个人中向右看并且没有被消除的人数的概率 如果第i+1个人是向右,$f[i+1][j+1]=f[i][j]/2$ 如果第i+1个人是向左,$f[i ...
- java面试题之能创建volatile数组吗?
答:能,只不过只是一个指向数组的引用,而不是整个数组,如果改变了引用指向的数组,将会受到volatile的保护,但是如果多个线程同时改变数组的元素,volatile关键字就不能起到保护的作用.
- System.out.println()和System.out.write()的区别
这两个函数一个是System.out.write()输出字符流,System.out.println()是输出字节流,很简单.看下面这个程序就明白了. //import java.util.* ...