客户端实现多个Memcached服务集群
Memcached服务器之间是独立的,没有任何关联,不能进行集群,Memcached集群是从客户端实现的。
应用系统使用统一的访问Memcached配置,在调用client包来set(key,value), get(key)时,使用相同选取服务器节点的算法,这样就实现了取到先前存入的对象。
选取服务器节点的算法思路是key的哈希值与节点数取模,比如,有Memcached服务器n0,n1,n2,n3,n4,key为"user_name",那么就是 hash(username)%5,如果结果为0就选取n0,依次类推。
选取服务器接点的算法一般封装在memcached client包中。
ArrayMemcachedSessionLocator:
KetamaMemcachedSessionLocator:
Memcached服务器之间是独立的,没有任何关联,不能进行集群,Memcached集群是从客户端实现的。
应用系统使用统一的访问Memcached配置,在调用client包来set(key,value), get(key)时,使用相同选取服务器节点的算法,这样就实现了取到先前存入的对象。
选取服务器节点的算法思路是key的哈希值与节点数取模,比如,有Memcached服务器n0,n1,n2,n3,n4,key为"user_name",那么就是 hash(username)%5,如果结果为0就选取n0,依次类推。
选取服务器接点的算法一般封装在memcached client包中。
MemcachedSession session = (MemcachedSession) this.findSessionByKey(msg .getKey());
//默认使用这个会话定位器
private MemcachedSessionLocator sessionLocator = new ArrayMemcachedSessionLocator();
// 使用一致性哈希算法(Consistent Hash Strategy) 建议使用。
builder.setSessionLocator(new KetamaMemcachedSessionLocator());
ArrayMemcachedSessionLocator:
public final long getHash(int size, String key) {
long hash = this.hashAlgorighm.hash(key);
return hash % size;
}
public final Session getSessionByKey(final String key) {
if (this.sessions == null || this.sessions.size() == 0) {
return null;
}
// Copy on read
List<List<Session>> sessionList = this.sessions;
int size = sessionList.size();
if (size == 0) {
return null;
}
long start = this.getHash(size, key);
List<Session> sessions = sessionList.get((int) start);
Session session = getRandomSession(sessions);
// If it is not failure mode,get next available session
if (!this.failureMode && (session == null || session.isClosed())) {
long next = this.getNext(size, start);
while ((session == null || session.isClosed()) && next != start) {
sessions = sessionList.get((int) next);
next = this.getNext(size, next);
session = getRandomSession(sessions);
}
}
return session;
}
KetamaMemcachedSessionLocator:
public final Session getSessionByKey(final String key) {
if (this.ketamaSessions == null || this.ketamaSessions.size() == 0) {
return null;
}
long hash = this.hashAlg.hash(key);
Session rv = this.getSessionByHash(hash);
int tries = 0;
while (!this.failureMode && (rv == null || rv.isClosed())
&& tries++ < this.maxTries) {
hash = this.nextHash(hash, key, tries);
rv = this.getSessionByHash(hash);
}
return rv;
}
public final Session getSessionByHash(final long hash) {
TreeMap<Long, List<Session>> sessionMap = this.ketamaSessions;
if (sessionMap.size() == 0) {
return null;
}
Long resultHash = hash;
if (!sessionMap.containsKey(hash)) {
// Java 1.6 adds a ceilingKey method, but xmemcached is compatible
// with jdk5,So use tailMap method to do this.
SortedMap<Long, List<Session>> tailMap = sessionMap.tailMap(hash);
if (tailMap.isEmpty()) {
resultHash = sessionMap.firstKey();
} else {
resultHash = tailMap.firstKey();
}
}
//
// if (!sessionMap.containsKey(resultHash)) {
// resultHash = sessionMap.ceilingKey(resultHash);
// if (resultHash == null && sessionMap.size() > 0) {
// resultHash = sessionMap.firstKey();
// }
// }
List<Session> sessionList = sessionMap.get(resultHash);
if (sessionList == null || sessionList.size() == 0) {
return null;
}
int size = sessionList.size();
return sessionList.get(this.random.nextInt(size));
}