转载:http://www.cnblogs.com/haippy/archive/2011/12/10/2282943.html
1致性哈希算法在1997年由麻省理工学院的Karger等人在解决散布式Cache中提出的,设计目标是为了解决因特网中的热门(Hot spot)问题,初衷和CARP10分类似。1致性哈希修正了CARP使用的简单哈希算法带来的问题,使得DHT可以在P2P环境中真正得到利用。
但现在1致性hash算法在散布式系统中也得到了广泛利用,研究过memcached缓存数据库的人都知道,memcached服务器端本身不提供散布式cache的1致性,而是由客户端来提供,具体在计算1致性hash时采取以下步骤:
从上图的状态中添加1台memcached服务器。余数散布式算法由于保存键的服务器会产生巨大变化而影响缓存的命中率,但Consistent Hashing中,只有在园(continuum)上增加服务器的地点逆时针方向的第1台服务器上的键会遭到影响,以下图所示:
斟酌到散布式系统每一个节点都有可能失效,并且新的节点极可能动态的增加进来,如何保证当系统的节点数目产生变化时依然能够对外提供良好的服务,这是值得斟酌的,特别实在设计散布式缓存系统时,如果某台服务器失效,对全部系统来讲如果不采取适合的算法来保证1致性,那末缓存于系统中的所有数据都可能会失效(即由于系统节点数目变少,客户端在要求某1对象时需要重新计算其hash值(通常与系统中的节点数目有关),由于hash值已改变,所以极可能找不到保存该对象的服务器节点),因此1致性hash就显得相当重要,良好的散布式cahce系统中的1致性hash算法应当满足以下几个方面:
平衡性是指哈希的结果能够尽量散布到所有的缓冲中去,这样可使得所有的缓冲空间都得到利用。很多哈希算法都能够满足这1条件。
单调性是指如果已有1些内容通过哈希分派到了相应的缓冲中,又有新的缓冲区加入到系统中,那末哈希的结果应能够保证原有已分配的内容可以被映照到新的缓冲区中去,而不会被映照到旧的缓冲集合中的其他缓冲区。简单的哈希算法常常不能满足单调性的要求,如最简单的线性哈希:x = (ax + b) mod (P),在上式中,P表示全部缓冲的大小。不难看出,当缓冲大小产生变化时(从P1到P2),原来所有的哈希结果均会产生变化,从而不满足单调性的要求。哈希结果的变化意味着当缓冲空间产生变化时,所有的映照关系需要在系统内全部更新。而在P2P系统内,缓冲的变化等价于Peer加入或退出系统,这1情况在P2P系统中会频繁产生,因此会带来极大计算和传输负荷。单调性就是要求哈希算法能够应对这类情况。
在散布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的1部份。当终端希望通过哈希进程将内容映照到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而致使哈希的结果不1致,终究的结果是相同的内容被不同的终端映照到不同的缓冲区中。这类情况明显是应当避免的,由于它致使相同内容被存储到不同缓冲中去,下降了系统存储的效力。分散性的定义就是上述情况产生的严重程度。好的哈希算法应能够尽可能避免不1致的情况产生,也就是尽可能下降分散性。
负载问题实际上是从另外一个角度看待分散性问题。既然不同的终端可能将相同的内容映照到不同的缓冲区中,那末对1个特定的缓冲区而言,也可能被不同的用户映照为不同的内容。与分散性1样,这类情况也是应当避免的,因此好的哈希算法应能够尽可能下降缓冲的负荷。
平滑性是指缓存服务器的数目平滑改变和缓存对象的平滑改变是1致的。
1致性哈希算法(Consistent Hashing)最早在论文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》中被提出。简单来讲,1致性哈希将全部哈希值空间组织成1个虚拟的圆环,如假定某哈希函数H的值空间为0⑵^32⑴(即哈希值是1个32位无符号整形),全部哈希空间环以下:
全部空间按顺时针方向组织。0和232⑴在零点中方向重合。
下1步将各个服务器使用Hash进行1个哈希,具体可以选择服务器的ip或主机名作为关键字进行哈希,这样每台机器就可以肯定其在哈希环上的位置,这里假定将上文中4台服务器使用ip地址哈希后在环空间的位置以下:
接下来使用以下算法定位数据访问到相应服务器:将数据key使用相同的函数Hash计算出哈希值,并肯定此数据在环上的位置,从此位置沿环顺时针“行走”,第1台遇到的服务器就是其应当定位到的服务器。
例如我们有Object A、Object B、Object C、Object D4个数据对象,经过哈希计算后,在环空间上的位置以下:
根据1致性哈希算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。
下面分析1致性哈希算法的容错性和可扩大性。现假定Node C不幸宕机,可以看到此时对象A、B、D不会遭到影响,只有C对象被重定位到Node D。1般的,在1致性哈希算法中,如果1台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前1台服务器(即沿着逆时针方向行走遇到的第1台服务器)之间数据,其它不会遭到影响。
下面斟酌另外1种情况,如果在系统中增加1台服务器Node X,以下图所示:
此时对象Object A、B、D不受影响,只有对象C需要重定位到新的Node X 。1般的,在1致性哈希算法中,如果增加1台服务器,则受影响的数据仅仅是新服务器到其环空间中前1台服务器(即沿着逆时针方向行走遇到的第1台服务器)之间数据,其它数据也不会遭到影响。
综上所述,1致性哈希算法对节点的增减都只需重定位环空间中的1小部份数据,具有较好的容错性和可扩大性。
另外,1致性哈希算法在服务节点太少时,容易由于节点分部不均匀而造成数据倾斜问题。例如系统中只有两台服务器,其环散布以下,
此时必定造成大量数据集中到Node A上,而只有极少许会定位到Node B上。为了解决这类数据倾斜问题,1致性哈希算法引入了虚拟节点机制,即对每个服务节点计算多个哈希,每一个计算结果位置都放置1个此服务节点,称为虚拟节点。具体做法可以在服务器ip或主机名的后面增加编号来实现。例如上面的情况,可以为每台服务器计算3个虚拟节点,因而可以分别计算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值,因而构成6个虚拟节点:
同时数据定位算法不变,只是多了1步虚拟节点到实际节点的映照,例如定位到“Node A#1”、“Node A#2”、“Node A#3”3个虚拟节点的数据均定位到Node A上。这样就解决了服务节点少时数据倾斜的问题。在实际利用中,通常将虚拟节点数设置为32乃至更大,因此即便很少的服务节点也能做到相对均匀的数据散布。
[1]. D. Darger, E. Lehman, T. Leighton, M. Levine, D. Lewin and R. Panigrahy. Consistent Hashing and Random Trees:Distributed Caching Protocols for Relieving Hot Spots On the World Wide Web. ACM Symposium on Theory of Computing, 1997. 1997:654⑹63.
[2]. 1致性哈希. http://baike.baidu.com/view/1588037.htm
[3]. memcached全面剖析–4. memcached的散布式算法. http://tech.idv2.com/2008/07/24/memcached-004/
[4]. 1致性哈希算法及其在散布式系统中的利用. http://www.codinglabs.org/html/consistent-hashing.html
[5]. Consistent hashing. http://en.wikipedia.org/wiki/Consistent_hashing
[6]. http://www.lexemetech.com/2007/11/consistent-hashing.html