一致性哈希(Consistent Hashing)

一:HashMap

谈论Consistent Hashing前,先回顾一下HashMap.

当使用HashMap时,key会被均匀的映射到hashMap内部数组中(Entry【】),映射方法利用key的hash值做移位运算,和entry数组的长度(Length-1)做与运算(和hashtable不同,(key.hashcode() & 0x7FFFFFFF) % table.length,使数据分散均匀分布)。

put操作时,当底层数组数据量超过LoadFactor(默认0.75)* len时,HashMap会按照2倍扩容的方式扩大底层数组的大小。put操作引进的新数据会按照上面提及的方法进行映射,但是之前已经映射的数据怎么办呢?HashMap源码中显示,resize()操作,每次扩容都会把之前已经映射的key重新映射。

所以对于HashMap而言,想要获得较好的性能必须要提前估计所放数据集合的大小,以设计合适的初始容量和负载因子。

二:定义

但不是每个场景都像HashMap这么简单,比如在大型的p2p网络中存在成百上千台server,资源和server的关系是以key的形式映射而成的,也就是说是一个大的HashMap,维护着每个资源在哪个server上,如果有新的节点加入或者退出该网络cluster,跟HashMap一样,也会导致映射关系发生变化,显然不可能吧所有的key和server的映射关系重新调整一遍,那会导致服务大量的未命中,直接导致服务不可用。这就需要一种方法,在新的server加入或者server的宕机,不需要调整所有的节点,而达到继续维护哈希映射的关系。因此一致性哈希定义为:

“Consistent hashing is schema that provides hash table functionlity in a way that the addition or removal of one slot does not significantly change the mapping of keys to the slots.(wiki)”;

就是说,“一致性哈希,就是提供一个hashtable,它能在节点的加入和离开时不会导致映射关系的重大变化”。

三:实现

一致性哈希的定义除了描述一个定义或者一种想法并没有给出任何实现方面的描述,所有细化的问题都留给开发者去思考,但一般的实现思想如下:

1:假定所有的资源以key的单向哈希(sha-1,sha-2,md5)均匀的分布在一个环上;

2:假定所有的节点(server)均匀的分布在该环上(以server的ip,port单向散列);

3:每个节点(server)只负责一部分Key,当节点加入、退出时只影响加入退出的节点和其邻居节点或者其他节点只有少量的Key受影响;

一般一致性哈希需要满足下面几个条件才对实际系统有意义:

1:平衡性(Balance):平衡性是指哈希的结果能够尽可能分布到所有的节点中去,这样可以使得所有的节点空间都得到利用。很多哈希算法都能够满足这一条件。

2:单调性(Monotonicity):单调性是指如果已经有一些内容通过哈希分派到了相应的节点中,又有新的节点加入到系统中。哈希的结果应能够保证原有已分配的内容可以被映射到原有的或者新的节点中去,而不会被映射到旧的节点集合中的其他节点上。

3:分散性(Spread):在分布式环境中,终端有可能看不到所有的缓存,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓存上时,由于不同终端所见的缓存范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓存区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓存中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。

4:负载(Load):负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。

环形Hash空间:


    按照常用的Hash算法来将对应的key哈希到一个具有2^32次方个桶的空间中,即0~(2^32)- 1的数字空间中。现在我们可以将这些数字头尾相连,想象成一个闭环,如下图:

把数据通过一定的hash算法处理后映射到环上:

     现在将object1, object2, object3, object4四个对象通过特定的hash函数计算出对应的key值,然后散列到Hash环上,如下图:

Hash(object1) = key1;

Hash (object2) = key2;

Hash (object3)  = key3;

Hash (object4)  =  key4;

具体hash算法,例如MD5 ->128bit, sha-2 -> 160bit,取前32bit组成一个integer,映射到该环上。

将机器通过Hash算法映射到环上: 

      在采用一致性哈希算法的分布式集群中将新的机器加入,其原理是通过使用与对象存储一样的hash素昂啊将机器也映射到环中(一般情况下对机器的hash计算是采用机器的IP或者机器唯一的别名和服务端口作为输入值),然后按顺时针方向计算,将所有对象存储到离自己最近的机器中。

假设现在有Node1, Node2, Node3三台机器,通过Hash算法得到对应的key值,映射到环中,其示意图如下:

Hash(NODE1) = KEY1;

Hash(NODE2) = KEY2;

Hash(NODE3) = KEY3;

通过上图可以看出对象和机器处于同一哈希空间中,这样按顺时针转到object1存储到NODE1中,object3存储到NODE2中, object2, object4存储到了Node3中。在这样的部署环境中,hash环是不会变更的,因此,通过算出对象的hash值就能快速的定位到对应的机器中,这样就能找到对象真正的存储位置了。

机器的删除与添加:

普通hash求余算法最为不妥的地方就是在有机器添加和删除之后会使大量的对象存储位置失效,这样就打打的不满足单调性,下面俩分析一下一致性哈希算法是如何处理的。

1:节点(机器)的删除

以上面的分布为例,如果NODE2出现故障删除了,那么按照顺时针迁移的方法,object3将会被迁移到NODE3中,这样仅仅是object3的映射位置发生了变化,其他的对象没有任何映射关系的改动。如下图:

2:节点(机器)的添加

如果往cluster中添加一个新的节点NODE4,通过对应的哈希算法得到KEY4,并映射到环中,如下图:

       通过按顺时针迁移的规则,那么object2被迁移到了NODE4中,其他对象还保持原来的映射关系(存储位置)。通过对节点的添加和删除分析,一致性哈希算法在保持了单调性的同事,还使数据的迁移达到最小,这样的算法对分布式cluster来说非常适合,避免了大量数据的迁移,减小了服务器的压力。

平衡性(数据分布均匀):

     根据上面的图解分析,一致性哈希算法满足了单调性和负载均衡的特性以及一般hash算法的分散性,但是这并不能当做其被广泛使用的原因,因为还缺少平衡性。下面将分析一致性哈希算法是如何满足平衡性的。hash算法是不保证平衡的,如上面只部署了NODE1和NODE3的情况(NODE2被删除的图), object1 存储到NODE1,而object2,object3,object4都被存储到了NODE3中,这样就是非常不平衡的状态,在一致性哈希算法中,为了尽可能的满足平衡性,其引入了虚拟节点:

-“虚拟节点”(virtual node)是实际节点(机器)在hash空间的复制品(replica),一实际节点(机器)对应了若干个“虚拟节点”,这个对应个数也成为“复制个数”,“虚拟节点”在hash空间中以hash值排列。

以上面只部署了NODE1和NODE3的情况为例,之前的对象在机器上分布很不均匀,现在我们以2个副本为例,这样整个hash环上就存在4个虚拟节点,最后对象映射的关系图如下:

"虚拟节点"的引入意义在于实际节点少而导致大片未被映射从而导致数据分布不均匀。假设每个server映射N个节点(N在100~200时较优),但key的hash映射到这N个节点实际上都有由该server托管,

根据上图可知对象的映射关系:object1-> NODE1-1, object2 -> NODE1-2,object3 -> NODE3-2, object4 -> NODE3-1.通过虚拟节点的引入,对象的分布比较均衡了,那么在实际操作中,真正的对象查询是如何工作的呢 ?对象从hash到虚拟节点到实际节点的转换如下图:

“虚拟节点”的hash计算可以采用对应实际节点的IP地址加上数字后缀的方法,加入假设NODE1的IP地址为192.168.1.100.引入“虚拟节点”前,计算cacheA的Hash值:

Hash("192.168.1.100");

引入“虚拟节点”后,计算“虚节点”点NODE1-1和NODE1-2的hash值:

Hash("192.168.1.100#1");//NODE1-1

Hash("192.168.1.100#2");//NODE1-2

有服务器台数(n)和增加的服务器台数(m)计算增加后的命中率如下:

(1 -  n / (n + m)) * 100

参考:http://blog.csdn.net/cywosp/article/details/23397179/

http://blog.charlee.li/memcached-004/

时间: 2024-08-25 03:29:16

一致性哈希(Consistent Hashing)的相关文章

Go语言实现一致性哈希(Consistent Hashing)算法

一致性哈希可用于解决服务器均衡问题. 用Golang简单实现了下,并加入了权重.可采用合适的权重配合算法使用. package main //一致性哈希(Consistent Hashing) //author: Xiong Chuan Liang //date: 2015-2-20 import ( "fmt" "hash/crc32" "sort" "strconv" "sync" ) const DE

深入一致性哈希(Consistent Hashing)算法原理,并附100行代码实现

本文为实现分布式任务调度系统中用到的一些关键技术点分享——Consistent Hashing算法原理和Java实现,以及效果测试. 背景介绍 一致性Hashing在分布式系统中经常会被用到, 用于尽可能地降低节点变动带来的数据迁移开销.Consistent Hashing算法在1997年就在论文Consistenthashing and random trees中被提出. 先来简单理解下Hash是解决什么问题.假设一个分布式任务调度系统,执行任务的节点有n台机器,现有m个job在这n台机器上运

一致性哈希(consistent hashing)算法

文章同步发表在博主的网站朗度云,传输门:http://www.wolfbe.com/detail/201608/341.html 1.背景 我们都知道memcached服务器是不提供分布式功能的,memcached的分布式完全是由客户端来实现的.在部署memcached服务器集群时,我们需要把缓存请求尽可能分散到不同的缓存服务器中,这样可以使得所有的缓存空间都得到利用,而且可以降低单独一台缓存服务器的压力.     最简单的一种实现是,缓存请求时通过计算key的哈希值,取模后映射到不同的memc

一致性哈希(Consistent Hashing)

传统来讲,数据的存储位置是通过hash(object)%N来计算的,这样造成的问题是如果新的机器添加进来或是某台机器down掉了,通过这种算法计算出来的存储位置会和以前的不同,造成了大量数据的迁移,如果有新的机器添加进来也会造成同样的问题,所以容错性和扩展性都不好.一致性哈希算法的主要目的是尽量减少数据的迁移. 一致性哈希假设有一个闭合圆环空间,上面有2**31个位置,数据通过特定的hash算法被分布到哈希圆环上.机器也通过特定的hash算法(输入值为机器的IP或是机器唯一的别名)放到圆环上,然

用于KV集群的一致性哈希Consistent Hashing机制

KV集群的请求分发 假定N为后台服务节点数,当前台携带关键字key发起请求时,我们通常将key进行hash后采用模运算 hash(key)%N 来将请求分发到不同的节点上, 后台节点的增删会引起几乎所有key的重新映射, 这样会造成大量的数据迁移,如果数据量大的话会导致服务不可用. 一致性哈希机制 我倾向于称之为一致性哈希机制而不是算法, 因为这其实和算法没太大关系. 设计这种机制的目的是当节点增减时尽量减小重新映射的key的数量, 尽量将key还映射到原来的节点上. 而对于一致性哈希机制, 如

一致性hash算法 – consistent hashing

consistent hashing 算法早在 1997 年就在论文 Consistent hashing and random trees 中被提出,目前在cache 系统中应用越来越广泛: 1 基本场景 比如你有 N 个 cache 服务器(后面简称 cache ),那么如何将一个对象 object 映射到 N 个 cache 上呢,你很可能会采用类似下面的通用方法计算 object 的 hash 值,然后均匀的映射到到 N 个 cache :澳门威尼斯人赌场 hash(object)%N

2016 -Nginx的负载均衡 - 一致性哈希 (Consistent Hash)

Nginx版本:1.9.1 算法介绍 当后端是缓存服务器时,经常使用一致性哈希算法来进行负载均衡. 使用一致性哈希的好处在于,增减集群的缓存服务器时,只有少量的缓存会失效,回源量较小. 在nginx+ats / haproxy+squid等CDN架构中,nginx/haproxy所使用的负载均衡算法便是一致性哈希. 我们举个例子来说明一致性哈希的好处. 假设后端集群包含三台缓存服务器,A.B.C. 请求r1.r2落在A上. 请求r3.r4落在B上. 请求r5.r6落在C上. 使用一致性哈希时,当

一致性hash算法 - consistent hashing

1.背景 我们都知道memcached服务器是不提供分布式功能的,memcached的分布式完全是由客户端来实现的.在部署memcached服务器集群时,我们需要把缓存请求尽可能分散到不同的缓存服务器中,这样可以使得所有的缓存空间都得到利用,而且可以降低单独一台缓存服务器的压力.     最简单的一种实现是,缓存请求时通过计算key的哈希值,取模后映射到不同的memcahed服务器.这种简单的实现在不考虑集群机器动态变化的情况下也是比较有效的一种方案,但是,在分布式集群系统中,简单取模的哈希算法

_00013 一致性哈希算法 Consistent Hashing 探讨以及相应的新问题出现解决

一.业务场景 假如我们现在有12台Redis服务器(其它的什么东西也行),有很多User(用户)的数据数据从前端过来,然后往12台redis服务器上存储,在存储中就会出现一个问题,12台服务器,有可能其中几台Redis服务器上(简称集群A)存了很多的数据,然后另外几台Redis服务器(简称集群B)上存的数据很少,这样的话那 A 上的读写压力就会很大(当然,这个要看你的数据量的大小了,如果你数据量很小的话,基本无压力了,但是数据量很大,那就 ...),对于这样的问题,我们通常的解决办法是什么呢 ?

_00013 一致性哈希算法 Consistent Hashing 新的讨论,并出现相应的解决

笔者博文:妳那伊抹微笑 博客地址:http://blog.csdn.net/u012185296 个性签名:世界上最遥远的距离不是天涯,也不是海角,而是我站在妳的面前.妳却感觉不到我的存在 技术方向:Flume+Kafka+Storm+Redis/Hbase+Hadoop+Hive+Mahout+Spark ... 云计算技术 转载声明:能够转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明,谢谢合作. qq交流群:214293307  idkey=bf80524ac3630cb09