memcached 之 哈希一致性 和 虚拟节点 分析
来源:互联网 发布:uwb定位算法 编辑:程序博客网 时间:2024/06/01 10:45
memcached 是一个简单高效的分布式内存缓存系统。
对于memcached service 来说,行为比较简单,存储key-value数据,并且memcached 相互之间并不通信,所以不能提供HA, load balance的功能。
这里的分布式实际是由客户端连接到不同的memcached,来做数据set/get 操作,这种数据分发行为完全是有客户端来做的, 客户端使用了哈希一致性和虚拟机节点来做这种数据分发。
考虑下面的场景
memcached 可以将一台或多台机器上的内存提供给多个application 使用。
如下图, 2个应用程序,3个memcached service, app1 和app2 可以使用3个service 提供的内存做cache,其操作api比较简单,get, set。
这里数据的distribution, 是由客户端app1 来做的,app 将数据以key 分发到不同的memcached。
客户端app并不记录某个数据记录在某个service 上(这样在数据量很大的时候,会出现性能的问题),
所以app 去get/set 某个数据的时候, app以key分配到不同的service上, 考虑最简答的模运算,如上场景有3个service(srvCount=3), 插入12个记录,分别hash(key) 分别为:
0,1,2,3,4,5,6,7,8,9,11,11
srvID = hash(key) % srv0 那么这六个数据的分布就是
srv0: 0,3,6,9
srv1: 1,4,7,10
srv2: 2,5,8,11
当我们增加一个memcached service (srv3)后,同样算法,就出现如下分布:
srv0: 0,4,8,
srv1: 1,5,9
srv2: 2,6,10
srv3: 3,7,11
这样发现数据分布跟之前的差距非常大,
考虑测试场景
1. app连接3个service, 插入10k个数据
2. 减少一个service, 查询插入的10k个数据,查看命中的几率
3. 增加一个service, 查询插入的10k个数据,查看命中的几率
像我们那样简答的模运算,当出现客户端app使用的service 出现增删的时候,就会出现大量数据不能命中,导致大量cache 失效, 哈希一致性算法就能增加这种增删service 时的命中率。
这里使用 memcache 的两个python 客户端库 python-memcached 和 pylibmc 来进行我们设定的场景测试
https://github.com/trumanz/pymemcached/blob/master/scale_test.py
python-memcached 只是简单取模运算, pylibmc 使用了 ketama 哈希一致性算法:结果如下
pylibmcpython-memcached删除memcached节点65.37000033.470000增加memcached 节点 73.70000025.620000
可以看出 ketama 哈希一直算法,在删除节点后,理论剩余66.67%的数据,其仍然能命中绝大部分剩余的数据,增加节点也能命中较多的数据,而python-memcached则有较大的cache失效。
1. ketama 哈希一致性算法
http://cn.last.fm/user/RJ/journal/2007/04/10/rz_libketama_-_a_consistent_hashing_algo_for_memcache_clients
哈希一致性算法,需要将server 地址做hash 运算,如下如图圆环A所示, 每个service 在圆环中占据不同的位置,数据做hash运算后在这个圆环上分配,分配到某个service的范围内是将数据分发到这个service上,(这样就在增删节点的时候server在圆圈上的位置不变从而增加了命中率)。
考虑增加节点的情况A-->B ,新加入的srv4 占据了一定范围的圆环,黄色部分原本分配到srv0的数据,现在指向了srv4, 这部分cache 就出现失效。
2. 虚拟节点
如上图,圆环A,B存在一个问题,就是数据不能均匀的分配到service上,并且当多个service 的内存大小不同时,也不能按照权重分配数据,这里引入了虚拟节点来解决这个问题,其实非常简单,就是将每个servie的地址由一个转变成更多的地址,
如srv1转变成srv1-0 和srv1-1 两种地址(也就是两个虚拟节点), 这样srv1 就能得到两个hash值,然后在圆环中占据两个位置,这样就变成了圆环C的情况,这样针对每个service 增加更多的虚拟节点就能实现按照权重的分配数据,如srv0有100M内存,srv1 有50M内存,那么
srv0可以由srv0-0,srv0-1, ..., srv0-99, 100个虚拟节点组成
srv1可以由srv1-0,srv1-1, ..., srv1-50, 50个虚拟节点组成
这样这些虚拟节点在圆环上的随机分配,一般就能保证数据按照权重分配到不同的service上。
测试代码如下,结果基本与pylibmc 一致
https://github.com/trumanz/pymemcached/blob/master/myketama.py
#!/usr/bin/env pythonimport sysfrom binascii import crc32import hashlibdef myhash(key): d = hashlib.md5(key).hexdigest() return [int(d[0:8], 16), int(d[8:16], 16), int(d[16:24], 16), int(d[24:32], 16)] return ((crc32(key) & 0xffffffff >> 16) & 0x7fff) or 1 class SRV: def __init__(self, addr): self.addr = addr self.keys = set() self.real_weight = 0 def __str__(self): return self.addr + ", has " + str(len(self.keys)) def __repr__(self): return str(self)srvs = []srvs_points = []def getSrv(key): l = 0 r = len(srvs_points) -1; v = myhash(key)[0] if r == 0: return k[0] if v >= srvs_points[r][0] or v < srvs_points[0][0]: return srvs_points[r][1] while (r - l) > 1: m = (l + r)/2 if v < srvs_points[m][0]: r = m else: l = m return srvs_points[l][1] def addSrv(addr): s = SRV(addr) srvs.append(s) for i in range(0,40): haddr = addr + '-' + str(i) hcode = myhash(haddr) for h in hcode: srvs_points.append((h, s)) srvs_points.sort(lambda p1, p2 : cmp(p1[0], p2[0]))def delSrv(addr): global srvs_points tmp = [x for x in srvs_points if x[1].addr != addr ] srvs_points = tmpif __name__ == '__main__': srvaddrs = ['SRV_A', 'SRV_B', 'SRV_C'] for addr in srvaddrs: addSrv(addr) for key in range(0, 10*1000): s = getSrv(str(key)) s.keys.add(key) print "After set 10K in 3 server" print "len of srvs_points=%d"%(len(srvs_points)) print srvs print "Test Add one Server" addSrv('SRV_D') print "len of srvs_points=%d"%(len(srvs_points)) hit = 0 for key in range(0, 10*1000): s = getSrv(str(key)) if key in s.keys: hit = hit+1 print " hit=%d"%(hit) print "Test del one Server" delSrv('SRV_D') delSrv('SRV_C') print "len of srvs_points=%d"%(len(srvs_points)) hit = 0 for key in range(0, 10*1000): s = getSrv(str(key)) if key in s.keys: hit = hit+1 print " hit=%d"%(hit)
root@test:~/pymemcached# ./myketama.py
After set 10K in 3 server
len of srvs_points=480
[SRV_A, has 3184, SRV_B, has 3300, SRV_C, has 3516]
Test Add one Server
len of srvs_points=640
hit=7245
Test del one Server
len of srvs_points=320
hit=6484
After set 10K in 3 server
len of srvs_points=480
[SRV_A, has 3184, SRV_B, has 3300, SRV_C, has 3516]
Test Add one Server
len of srvs_points=640
hit=7245
Test del one Server
len of srvs_points=320
hit=6484
0 0
- memcached 之 哈希一致性 和 虚拟节点 分析
- memcached 之 哈希一致性 和 虚拟节点 分析
- 一致性哈希的虚拟节点
- Cassandra的一致性哈希(Consistent Hashing)和虚拟节点(Virtual Nodes)的关系
- 使用虚拟节点改进的一致性哈希算法
- memcached:一致性哈希算法
- memcached分布式-一致性哈希
- memcached一致性哈希算法
- PHP学习之memcached一致性哈希算法
- memcached 技术细节( 工作原理、内存模型、缓存算法、一致性hash、虚拟节点)
- 一致性HASH算法(虚拟节点)
- Jedis之ShardedJedis一致性哈希分析
- Jedis之ShardedJedis一致性哈希分析
- Jedis之ShardedJedis一致性哈希分析
- libmemcached一致性hash算法详解(1)----php-memcached客户端一致性哈希与crc算法共用产生的bug分析
- memcached一致性哈希的php类
- memcached分布式一致性哈希算法
- 利用一致性哈希的memcached类
- C++学习笔记(3) 数组
- com.android.camera.Camera.java,主要的实现Activity,继承于ActivityBase
- 15回文相关问题
- Android官网开发文档API
- VMware虚拟机配置Ubuntu桥接方式(Bridged)使虚拟机和宿主机能互相ping通
- memcached 之 哈希一致性 和 虚拟节点 分析
- Android.mk 参数函数查询
- 重装Win7后找回Ubuntu启动项并在Ubuntu中修复引导
- EL表达式
- C++静态成员类内初始化注意事项
- 养成写博客的好习惯,记录学习过程中的点滴和收藏不错的东西
- Linux压缩解压命令大全
- Linux使用 tar命令-g参数进行增量+差异备份、还原文件
- [POJ_1068]Parencodings