![bcbdae9842e7b60d3d722e6734edb51f.png](https://i-blog.csdnimg.cn/blog_migrate/a14090e2238479e7420eb0f3e57c0ad9.jpeg)
memcache的分布式原理
memcached 虽然称为 “ 分布式 ” 缓存服务器,但服务器端并没有 “ 分布式 ” 功能。每个服务器都是完全独立和隔离的服务。memcached 的分布式,则是完全由客户端程序库实现的。这种分布式是 memcached 的最大特点。
memcache的内存分配机制
如何存放数据到memcached缓存中?(memcache内存分配机制)
Slab Allocator内存分配机制:
预先将内存分配成数个slab仓库,每个仓库再切出不同大小的chunk,去适配收到的数据。多余的只能造成浪费,不可避免。
增长因子(Grace factor):一般而言观察数据大小的变化规律设置合理的增长因子,默认1.25倍.
太大容易造成浪费。memcached.exe -m 64 -p 11211 -f 1.25
如果有100byte的内容要存储,但122大小的仓库的chunk用满了怎么办?
答:是并不会寻找更大仓库的chunk来存储,而是把122仓库中的旧数据踢掉!
memcache的惰性失效机制
1 当某个值过期后并不会从内存删除。(因此status统计时的curr_items有其信息)
2 如果之前没有get过,将不会自动删除。
如果(过期失效,没get过一次)又没有一个新值去占用他的位置时,当做空的chunk占用。
3 当取其值(get)时,判断是否过期:如果过期返回空,且清空。(所以curr_items就减少了)
即这个过期只是让用户看不到这个数据而已,并没有在过期的瞬间立即从内存删除,这个过程
称为lazy expirtion,属性失效,好处是节约了cpu和检测的成本,称为“惰性失效机制”
memcache缓存的无底洞现象
缓存的无底洞现象:
facebook的工作人员反应,他们在2010年左右,memcacahed节点就已经达到3000个,大约数千G的缓存,他们发现一个问题,memchache连接频率太高导致效率下降,于是加memcache节点,添加后发现连接频率导致的问题仍然没有好转,称之为“无底洞现象”。
问题分析:
以用户为例:user-133-age,user-133_name,user-133-height…N个key
当服务器增多,133号用户的信息也被散落在更多的服务器,
所以同样是访问个人主页,得到相同的个人信息,节点越多,要连接节点越多,对于memcache的连接数并没有随着节点的增多而降低,问题出现。
事实上:
nosql和传统的rdbms并不是水火不容,两者在某些设计上是可以相互参考的。
对于nosql的key-value这种存储,key的设计可以参考mysql中表和列的设计。
比如user表下有age、name、height列,对应的key可以用user:133:age=23,user:133:name=ls,user:133:height=168;
问题的解决方案:
把某一组key按其共同前缀来分布,比如:user:133:age=23,user:133:name=ls,user:133:height=168;
在用分布式算法求其节点时,应该以user:133来计算,而不是以user:133:age来计算,这样这三个关于个人信息的key都落在同一个节点上。
再次访问只需要连接一个节点。问题解决。
一致性Hash算法的实现原理
Hash环
我们把232次方想成一个环,比如钟表上有60个分针点组成一个圆,那么hash环就是由232个点组成的圆。第一个点是0,最后一个点是232-1,我们把这232个点组成的环称之为HASH环。
一致性Hash算法
将memcached物理机节点通过Hash算法虚拟到一个虚拟闭环上(由0到232构成),key请求的时候通过Hash算法计算出Hash值然后对232取模,定位到环上顺时针方向最接近的虚拟物理节点就是要找到的缓存服务器。
假设有ABC三台缓存服务器:
我们使用这三台服务器各自的IP进行hash计算然后对2~32取模即:
Hash(服务器IP)%2~32
计算出来的结果是0到2~32-1的一个整数,那么Hash环上必有一个点与之对应。比如:
现在缓存服务器已经落到了Hash环上,接下来我们就看我们的数据是怎么放到缓存服务器的?
我们可以同样对Object取Hash值然后对2~32取模,比如落到了接近A的一个点上:
那么这个数据理应存到A这个缓存服务器节点上
所以,在缓存服务器节点数量不变的情况下,缓存的落点是不会变的。
但是如果B挂掉了呢?
按照hash且取模的算法,图中3这个Object理应就分配到了C这个节点上去了,所以就会到C上找缓存数据,结果当然是找不到,进而从DB读取数据重新放到了C上。
但是对于编号为1,2的Object还是落到A,编号为4的Object还是落到C,B宕机所影响的仅仅是3这个Object。这就是一致性Hash算法的优点。
Hash环的倾斜
前面我们理想化的把三台memcache机器均匀分到了Hash环上:
但是现实情况可能是:
如果Hash环倾斜,即缓存服务器过于集中将会导致大量缓存数据被分配到了同一个服务器上。比如编号1,2,3,4,6的Object都被存到了A,5被存到B,而C上竟然一个数据都没有,这将造成内存空间的浪费。
为了解决这个问题,一致性Hash算法中使用“虚拟节点”解决。
虚拟节点解决Hash环倾斜
“虚拟节点”是“实际节点”在hash环上的复制品,一个实际节点可能对应多个虚拟节点。这样就可以将ABC三台服务器相对均匀分配到Hash环上,以减少Hash环倾斜的影响,使得缓存被均匀分配到hash环上。
hash算法平衡性
平衡性指的是hash的结果尽可能分布到所有的缓存中去,这样可以使得所有的缓存空间都可以得到利用。但是hash算法不保证绝对的平衡性,为了解决这个问题一致性hash引入了“虚拟节点”的概念。虚拟节点”( virtual node )是实际节点在 hash 空间的复制品( replica ),一实际个节点对应了若干个“虚拟节点”,这个对应个数也成为“复制个数”,“虚拟节点”在 hash 空间中以 hash 值排列。“虚拟节点”的hash计算可以采用对应节点的IP地址加数字后缀的方式。
例如假设 cache A 的 IP 地址为202.168.14.241 。
引入“虚拟节点”前,计算 cache A 的 hash 值:Hash(“202.168.14.241”);
引入“虚拟节点”后,计算“虚拟节”点 cache A1 和 cache A2 的 hash 值:
Hash(“202.168.14.241#1”); // cache A1
Hash(“202.168.14.241#2”); // cache A2
这样只要是命中cacheA1和cacheA2节点,就相当于命中了cacheA的缓存。这样平衡性就得到了提高。
memcached与redis的区别
1 redis做存储,可以持久化,memcache做缓存,数据易丢失。
2 redis支持多数据类型,memcache存放字符串。
3 redis服务端仅支持单进程、单线程访问,也就是先来后到的串行模式,避免线程上下文切换,自然也就保证数据操作的原子性。Memcache服务端是支持多线程访问的。
4 redis虽然是单进程单线程模式,但是redis使用了IO多路复用技术做到一个线程可以处理很多个请求来保证高性能。
最后,我自己是一名从事了多年开发的JAVA老程序员,今年年初我花了一个月整理了一份最适合2019年学习的java学习干货,可以送给每一位喜欢java的小伙伴,想要获取的可以关注我的头条号并在后台私信我:java,即可免费获取。
作者:Jeff.Smile
来源:微信公众号