`
BradyZhu
  • 浏览: 247970 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

【总结】一致性哈希算法(Memcached)

 
阅读更多

一、概述

1、我们的memcache客户端使用了一致性hash算法ketama进行数据存储节点的选择。与常规的hash算法思路不同,只是对我们要存储数据的key进行hash计算,分配到不同节点存储。一致性hash算法是对我们要存储数据的服务器进行hash计算,进而确认每个key的存储位置。

2、常规hash算法的应用以及其弊端

最常规的方式莫过于hash取模的方式。比如集群中可用机器适量为N,那么key值为K的的数据请求很简单的应该路由到hash(K) mod N对应的机器。的确,这种结构是简单的,也是实用的。但 是在一些高速发展的web系统中,这样的解决方案仍有些缺陷。随着系统访问压力的增长,缓存系统不得不通过增加机器节点的方式提高集群的相应速度和数据承 载量。增加机器意味着按照hash取模的方式,在增加机器节点的这一时刻,大量的缓存命不中,缓存数据需要重新建立,甚至是进行整体的缓存数据迁移,瞬间 会给DB带来极高的系统负载,设置导致DB服务器宕机。

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键的重新分布。另外要取得比较好的负载均衡的效果,往往在服务器数量比较少的时候需要增加虚拟节点来保证服务器能均匀的分布在圆环上。因为使用一般的hash方法,服务器的映射地点的分布非常不均匀。使用虚拟节点的思想,为每个物理节点(服务器)在圆上分配100~200个点。这样就能抑制分布不均匀,最大限度地减小服务器增减时的缓存重新分布。用户数据映射在虚拟节点上,就表示用户数据真正存储位置是在该虚拟节点代表的实际物理服务器上。
下面有一个图描述了需要为每台物理服务器增加的虚拟节点。



三、以spymemcache源码来演示虚拟节点应用

1、上边描述的一致性Hash算法有个潜在的问题是:
(1)、将节点hash后会不均匀地分布在环上,这样大量key在寻找节点时,会存在key命中各个节点的概率差别较大,无法实现有效的负载均衡。
(2)、如有三个节点Node1,Node2,Node3,分布在环上时三个节点挨的很近,落在环上的key寻找节点时,大量key顺时针总是分配给Node2,而其它两个节点被找到的概率都会很小。

2、这种问题的解决方案可以有:
改善Hash算法,均匀分配各节点到环上;[引文]使用虚拟节点的思想,为每个物理节点(服务器)在圆上分配100~200个点。这样就能抑制分布不均 匀,最大限度地减小服务器增减时的缓存重新分布。用户数据映射在虚拟节点上,就表示用户数据真正存储位置是在该虚拟节点代表的实际物理服务器上。

在查看Spy Memcached client时,发现它采用一种称为Ketama的Hash算法,以虚拟节点的思想,解决Memcached的分布式问题。

3、源码说明

该client采用TreeMap存储所有节点,模拟一个环形的逻辑关系。在这个环中,节点之前是存在顺序关系的,所以TreeMap的key必须实现Comparator接口。
那节点是怎样放入这个环中的呢?

复制代码
 1     protected void setKetamaNodes(List<MemcachedNode> nodes) {
 2     TreeMap<Long, MemcachedNode> newNodeMap = new TreeMap<Long, MemcachedNode>();
 3     int numReps= config.getNodeRepetitions();
 4     for(MemcachedNode node : nodes) {
 5         // Ketama does some special work with md5 where it reuses chunks. 6         if(hashAlg == HashAlgorithm.KETAMA_HASH) {
 7             for(int i=0; i<numReps / 4; i++) {
 8                 byte[] digest=HashAlgorithm.computeMd5(config.getKeyForNode(node, i));
 9                 for(int h=0;h<4;h++) {
10                     Long k = ((long)(digest[3+h*4]&0xFF) << 24)
11                         | ((long)(digest[2+h*4]&0xFF) << 16)
12                         | ((long)(digest[1+h*4]&0xFF) << 8)
13                         | (digest[h*4]&0xFF);
14                     newNodeMap.put(k, node);
15                     getLogger().debug("Adding node %s in position %d", node, k);
16                 }
17 
18             }
19         } else {
20             for(int i=0; i<numReps; i++) {
21                 newNodeMap.put(hashAlg.hash(config.getKeyForNode(node, i)), node);
22             }
23         }
24     }
25     assert newNodeMap.size() == numReps * nodes.size();
26     ketamaNodes = newNodeMap;


上面的流程大概可以这样归纳:四个虚拟结点为一组,以getKeyForNode方法得到这组虚拟节点的name,Md5编码后,每个虚拟 结点对应Md5码16个字节中的4个,组成一个long型数值,做为这个虚拟结点在环中的惟一key。第10行k为什么是Long型的呢?就是因为 Long型实现了Comparator接口。

处理完正式结点在环上的分布后,可以开始key在环上寻找节点的游戏了。
对于每个key还是得完成上面的步骤:计算出Md5,根据Md5的字节数组,通过Kemata Hash算法得到key在这个环中的位置。

五、总结

1、一致性hash算法只是帮我们减少cache集群中的机器数量增减的时候,cache的数据能进行最少重建。只要cache集群的server数量有变化,必然产生数据命中的问题

2、对于数据的分布均衡问题,通过虚拟节点的思想来达到均衡分配。当然,我们cache server节点越少就越需要虚拟节点这个方式来均衡负载。


3、我们的cache客户端根本不会维护一个map来记录每个key存储在哪里,都是通过key的hash和cacheserver(也许ip可以作为参数)的hash计算当前的key应该存储在哪个节点上。
分享到:
评论

相关推荐

    一致性哈希算法源码 Ketama一致性hash算法源码

    Ketama算法是一致性hash算法的一个优秀实现。增删节点后数据命中率及均分率都很高。

    memcached:在Node.js之上构建的功能齐全的Memcached客户端。 考虑到扩展性,因此它将支持Memcached集群和一致的哈希

    一致性哈希是一种提供哈希表功能的方案,该方式使得添加或删除服务器节点不会显着更改密钥到服务器节点的映射。 用于一致性哈希的算法与libketama相同。 例如,有多种处理错误的方法,例如,当服务器不可用时,您...

    ist的matlab代码-hash_ring:在Python中实现一致的哈希(使用md5作为哈希函数)

    一致性哈希是一种以提供或删除一个插槽不会显着改变键到插槽的映射的方式提供哈希表功能的方案。 可以在博客文章中阅读有关hash_ring的更多信息(该文章更详细地解释了该想法): 一致的散列仅在python中实现 这些...

    memcached权威指南

    讲述memcached 安装使用等 ...第七章 一致性哈希算法实验课.....................................................................................................26 7.1 实验目的...............................

    NoSQL数据库笔谈.pdf

    手段篇 一致性哈希 亚马逊的现状 算法的选择 Quorum NRW Vector clock Virtual node gossip Gossip (State Transfer Model) Gossip (Operation Transfer Model) Merkle tree Paxos 背景 DHT Map Reduce Execution ...

    NoSQL数据库笔谈

    3. 手段篇 一致性哈希 亚马逊的现状 算法的选择 Quorum NRW Vector clock Virtual node gossip Gossip (State Transfer Model) Gossip (Operation Transfer Model) Merkle tree Paxos 背景 DHT Map Reduce Execution...

    大数据云计算技术系列 NoSQL数据库学习教程(共71页).pdf

    3 一致性哈希 3 亚马逊的现状 3 算法的选择 3 Quorum NRW 3 Vector clock 3 Virtual node 3 gossip 3 Gossip (State Transfer Model) 3 Gossip (Operation Transfer Model) 3 Merkle tree 3 Paxos 3 背景 3 DHT 3 ...

    9、缓存(10题)1

    1. 列举一个常用的Redis客户端的并发模型 2. 如何实现一个Hashtable 3. 分布式缓存,一致性hash 4. LRU算法, slab分配,如何减

    09、缓存(10题)1

    1. 列举一个常用的Redis客户端的并发模型 2. 如何实现一个Hashtable 3. 分布式缓存,一致性hash 4. LRU算法, slab分配,如何减

    nosql 入门教程

    4.5.1 一致性哈希 81 4.5.2 对象版本 82 4.5.3 闲话协议和提示移交 83 4.6 小结 83 第5章 执行CRUD操作 84 5.1 创建记录 84 5.1.1 在以文档为中心的数据库中创建记录 85 5.1.2 面向列数据库的创建操作 91 ...

    Redis面试题50道(含答案)_.pdf

    39、支持一致性哈希的客户端有哪些? 40、Redis 与其他 key-value 存储有什么不同? 41、Redis 的内存占用情况怎么样? 42、都有哪些办法可以降低 Redis 的内存使用情况呢? 43、查看 Redis 使用情况及状态信息用...

Global site tag (gtag.js) - Google Analytics