一致性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接口。

那节点是如何放入这个环中的呢?

[html] view plaincopyprint?

  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. } else {
  19. for(int i=0; i<numReps; i++) {
  20. newNodeMap.put(hashAlg.hash(config.getKeyForNode(node, i)), node);
  21. }
  22. }
  23. }
  24. assert newNodeMap.size() == numReps * nodes.size();
  25. 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在这个环中的位置。

[html] view plaincopyprint?

  1. MemcachedNode getNodeForKey(long hash) {
  2. final MemcachedNode rv;
  3. if(!ketamaNodes.containsKey(hash)) {
  4. // Java 1.6 adds a ceilingKey method, but I‘m still stuck in 1.5
  5. // in a lot of places, so I‘m doing this myself.
  6. SortedMap<Long, MemcachedNode> tailMap=getKetamaNodes().tailMap(hash);
  7. if(tailMap.isEmpty()) {
  8. hash=getKetamaNodes().firstKey();
  9. } else {
  10. hash=tailMap.firstKey();
  11. }
  12. }
  13. rv=getKetamaNodes().get(hash);
  14. return rv;
  15. }
	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

时间: 2024-12-09 05:15:14

一致性hash算法在memcached中的使用的相关文章

(转) 一致性Hash算法在Memcached中的应用

前言 大家应该都知道Memcached要想实现分布式只能在客户端来完成,目前比较流行的是通过一致性hash算法来实现.常规的方法是将 server的hash值与server的总台数进行求余,即hash%N,这种方法的弊端是当增减服务器时,将会有较多的缓存需要被重新分配且会造成缓 存分配不均匀的情况(有可能某一台服务器分配的很多,其它的却很少). 今天分享一种叫做”ketama”的一致性hash算法,它通过虚拟节点的概念和不同的缓存分配规则有效的抑制了缓存分布不均匀,并最大限度地减少服务器增减时缓

一致性hash算法在内存数据库中的应用

由于redis是单点,但是项目中不可避免的会使用多台Redis缓存服务器,那么怎么把缓存的Key均匀的映射到多台Redis服务器上,且随着缓存服务器的增加或减少时做到最小化的减少缓存Key的命中率呢?这样就需要我们自己实现分布式. Memcached对大家应该不陌生,通过把Key映射到Memcached Server上,实现快速读取.我们可以动态对其节点增加,并未影响之前已经映射到内存的Key与memcached Server之间的关系,这就是因为使用了一致性哈希.因为Memcached的哈希策

一致性Hash算法及使用场景

一.问题产生背景      在使用分布式对数据进行存储时,经常会碰到需要新增节点来满足业务快速增长的需求.然而在新增节点时,如果处理不善会导致所有的数据重新分片,这对于某些系统来说可能是灾难性的. 那么是否有可行的方法,在数据重分片时,只需要迁移与之关联的节点而不需要迁移整个数据呢?当然有,在这种情况下我们可以使用一致性Hash来处理. 二.一致性Hash算法背景 一致性哈希算法在1997年由麻省理工学院的Karger等人在解决分布式Cache中提出的,设计目标是为了解决因特网中的热点(Hot

[转载] 一致性hash算法释义

转载自http://www.cnblogs.com/haippy/archive/2011/12/10/2282943.html 一致性Hash算法背景 一致性哈希算法在1997年由麻省理工学院的Karger等人在解决分布式Cache中提出的,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简单哈希算法带来的问题,使得DHT可以在P2P环境中真正得到应用. 但现在一致性hash算法在分布式系统中也得到了广泛应用,研究过memcach

一致性Hash算法背景

一致性Hash算法背景 一致性哈希算法在1997年由麻省理工学院的Karger等人在解决分布式Cache中提出的,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简单哈希算法带来的问题,使得DHT可以在P2P环境中真正得到应用. 但现在一致性hash算法在分布式系统中也得到了广泛应用,研究过memcached缓存数据库的人都知道,memcached服务器端本身不提供分布式cache的一致性,而是由客户端来提供,具体在计算一致性has

OpenStack_Swift源代码分析——Ring基本原理及一致性Hash算法

1.Ring的基本概念 Ring是swfit中最重要的组件.用于记录存储对象与物理位置之间的映射关系,当用户须要对Account.Container.Object操作时,就须要查询相应的Ring文件(Account.Container.Object都有自己相应的Ring),Ring 使用Region(近期几个版本号中新增加的).Zone.Device.Partition和Replica来维护这些信息,对于每个对象,依据你在部署swift设置的Replica数量,集群中会存有Replica个对象.

OpenStack_Swift源码分析——Ring基本原理及一致性Hash算法

1.Ring的基本概念 Ring是swfit中最重要的组件,用于记录存储对象与物理位置之间的映射关系,当用户需要对Account.Container.Object操作时,就需要查询对应的Ring文件(Account.Container.Object都有自己对应的Ring),Ring 使用Region(最近几个版本中新加入的).Zone.Device.Partition和Replica来维护这些信息,对于每一个对象,根据你在部署swift设置的Replica数量,集群中会存有Replica个对象.

一致性hash算法及java实现

一致性hash算法是分布式中一个常用且好用的分片算法.或者数据库分库分表算法.现在的互联网服务架构中,为避免单点故障.提升处理效率.横向扩展等原因,分布式系统已经成为了居家旅行必备的部署模式,所以也产出了几种数据分片的方法: 1.取模,2.划段,3.一致性hash 前两种有很大的一个问题就是需要固定的节点数,即节点数不能变,不能某一个节点挂了或者实时增加一个节点,变了分片规则就需要改变,需要迁移的数据也多. 那么一致性hash是怎么解决这个问题的呢? 一致性hash:对节点和数据,都做一次has

分布式memcached学习(四)&mdash;&mdash; 一致性hash算法原理

    分布式一致性hash算法简介 当你看到"分布式一致性hash算法"这个词时,第一时间可能会问,什么是分布式,什么是一致性,hash又是什么.在分析分布式一致性hash算法原理之前,我们先来了解一下这几个概念. 分布式 分布式(distributed)是指在多台不同的服务器中部署不同的服务模块,通过远程调用协同工作,对外提供服务. 以一个航班订票系统为例,这个航班订票系统有航班预定.网上值机.旅客信息管理.订单管理.运价计算等服务模块.现在要以集中式(集群,cluster)和分布