Memcached学习笔记(2)一Memcached分布式
memcached虽然称为“分布式”缓存服务器,但服务器端并没有“分布式”功能。服务器只是实现了内存存储的功能,至于memcached的分布式,则是完全由客户端程序库实现的。通过memcached的客户端路由实现memcached集群环境,这种分布式是memcached的最大特点。
客户端做路由
客户端做路由的原理非常简单,应用服务器在每次存取某key的value时,通过某种算法把key映射到某台memcached服务器nodeA上,因此这个key所有操作都在nodeA上,结构图如下所示:
存储某个key-value,客户端程序根据某种算法获得存取此value的服务器,存入该服务器中,如下图:
取某个key-value,根据key,同样的算法获取存取该key对应value的服务器。
因此关键在于算法的选择,最基本的要求就是能让数据平均到所有服务器上。spymemcached是一个用得比较广的java客户端,它就提供了一种简单的hash算法,实现类为ArrayModNodeLocator,从key映射到node的源码如下:
public MemcachedNode getPrimary(String k) { return nodes[getServerForKey(k)]; } private int getServerForKey(String key) { int rv = (int) (hashAlg.hash(key) % nodes.length); assert rv >= 0 : "Returned negative key for key " + key; assert rv < nodes.length : "Invalid server number " + rv + " for key " + key; return rv; }
由上可知所有的note都被放到数组中,通过hash取模的算法获得note数组中的某一个服务器。当添加一个note或删除一个note的时候,找不到对应的note该怎么办,上面的策略是在数据组里顺序向下轮询node,找第一个工作正常的node。很显然这种方式是有问题的,note发生变化了,将导致大量的key找不到其原来所对应的note,从而会重新将值放置到新的note服务器中。如何解决这个问题呢?分布式这块有一个算法“hash一致性算法”可以很好的解决这个问题,关于hash一致性算法,博文分布式设计与开发(二)------几种必须了解的分布式算法 讲的比较细致。spymemcache 的KetamaNodeLocator类就实现了这种算法,源码如下:
public MemcachedNode getPrimary(final String k) { MemcachedNode rv = getNodeForKey(hashAlg.hash(k)); assert rv != null : "Found no node for key " + k; return rv; } MemcachedNode getNodeForKey(long hash) { final MemcachedNode rv; if (!ketamaNodes.containsKey(hash)) { //tailMap(key):返回treemap中大于或等于key的对象构建的map SortedMap<Long, MemcachedNode> tailMap = getKetamaNodes().tailMap(hash); if (tailMap.isEmpty()) { hash = getKetamaNodes().firstKey(); } else { hash = tailMap.firstKey(); } } rv = getKetamaNodes().get(hash); return rv; }
memcached服务端集群
由上面可知一般的应用中memcached服务端集群不用做太多工作,部署一堆memcached服务器就可以了。