近来在看Memcached的原理,将学习的东西记录一下。前面4节是网上转载的。
Memcached是一个免费开源的,高性能的,具有分布式对象的缓存系统,它可以用来保存一些经常存取的对象或数据,保存的数据像一张巨大的hash表,该表以Key-value对的方式存在内存中。它实现了客户端的分布式缓存,但没有实现服务端的分布式。
所谓分布式,就是将不同的键值保存到不同的服务器上,这样就实现了memcached的分布式。Memcached服务器增多以后,键就会分散,即使一台memcached服务器挂掉,也影响不大。
1 操作流程
- 检查客户端的请求数据是否在memcached中,如有,直接把请求数据返回,不再对数据库进行任何操作。
- 如果请求的数据不在memcached中,就去查数据库,把从数据库中获取的数据返回给客户端,同时把数据缓存一份到memcached中(memcached客户端不负责,需要程序明确实现)
- 每次更新数据库的同时更新memcached中的数据,保证一致性。
- 当分配给memcached内存空间用完之后,会使用LRU(Least Recently Used,最近最少使用)策略加上到期失效策略,失效数据首先被替换,然后再替换掉最近未使用的数据。
2 内存管理机制
目前的memcached采用的是Slab Allocation机制:整理内存以便重复使用。在这之前,内存管理基于malloc和free来进行的。但是这种方式会产生内存碎片,加重操作系统的负担,在最坏的情况下,可能操作系统比memcached系统还要慢。
3 Memcached的缓存策略:
Memcached的缓存策略是LRU(最近最少使用)加上到期失效策略。当你在memcached内存储数据项时,你有可能会指定它在缓存的失效时间,默认为永久。当memcached服务器用完分配的内时,失效的数据被首先替换,然后也是最近未使用的数据。在LRU中,memcached使用的是一种 Lazy Expiration策略,自己不会监控存入的key/vlue对是否过期,而是在获取key值时查看记录的时间戳,检查key/value对空间是否过期,这样可减轻服务器的负载。
4 Memcached的分布式算法:
所谓分布式算法就是确定保存的时候对象应该放在哪个服务器上,通过key取值的时候,应该去哪个服务器寻找数据。这一进一出的两个过程,只要保证相同的位置计算算法就可以。
4.1余数算法:
先求得键的整数散列值,再除以服务器台数,根据余数确定存取服务器,这种方法计算简单,高效,但在memcached服务器增加或减少时,几乎所有的缓存都会失效。
4.2 散列算法(一致性hash算法)
先算出memcached服务器的散列值,并将其分布到0到2的32次方的圆上,然后用同样的方法算出存储数据的键的散列值并映射至圆上,最后从数据映射 到的位置开始顺时针查找,将数据保存到查找到的第一个服务器上,如果超过2的32次方,依然找不到服务器,就将数据保存到第一台memcached服务器 上。如果添加了一台memcached服务器,只在圆上增加服务器的逆时针方向的第一台服务器上的键会受到影响。
5 如何降低新增机器对服务器节点分布的影响
如上图影响范围所示,新加入的节点node5,它相当于分担了node4节点的一部分压力,假设这部分是50%,那么在加入之前的状态,node4与其他3个节点承受的压力是等同的,现在新加入node5后,意味着node1 node2 node3的压力是node4 node5的两倍,这显然不是我们想要的结果。那么该如何解决这样的问题?可以通过增加虚拟层来解决。将每台缓存服务器虚拟为一组缓存服务器,将虚拟服务器的Hash值放在Hash环上,Key在环上先找到虚拟服务器节点,再得到物理服务器的信息。
这样在新加入物理服务器节点时,是将一组虚拟节点加入环中,如果虚拟节点的数量足够多,这组虚拟节点将会影响同样多数目的已经在环上的虚拟节点。这些已经存在的虚拟节点又对应不同的物理节点。最终结果是:新加入一台缓存服务器,将会较为均匀的将影响分散到多台服务器上,也就是分摊一小部分负载。
如上图所示,原有物理节点N1,N2,N3,将他们分别虚拟为三个节点。新加入节点N4,虚拟为N41,N42,N43,可以看到它影响的是分别是N20,N31,N11,相当于对每个原有节点都有了一些影响。当然这是最理想的情况,在这种情况下,每个物理节点被影响的数据(储存在物理节点中,但不能访问)的数量为1/4(X(N+X)),N为原物理节点数,X为新加入的节点数。也就是集群中已有的75%的数据可以连续命中,这与没有虚拟层的结果是一样的,但每个服务器的压力却是均匀分布的。