1.几个特性
- 单调性
单调性是指如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲区加入到系统中,那么哈希的结果应能够保证原有已分配的内容可以被映射到新的缓冲区中去,而不会被映射到旧的缓冲集合中的其他缓冲区。
有点绕,简单来说就是,如果添加一个新节点,原有的key对应的缓存,要么不迁移,要么迁移到新的节点,而不会迁移到其他旧节点。
- 均衡性
均衡性就是指hash的结果要尽可能地均分到所有的缓存节点中。 - 分散性
分散性是指同一个key对应的缓存仅放在一个节点上,每次访问也能访问到。而不用多个节点上保存相同的内容。
2.Java版本实现
public class LZHash {
static List<String> realNodes = new ArrayList<String>();
int replcaNum = 50;//虚拟节点副本数量,需要大一些,能更好地保证均衡性
static SortedMap<Integer, String> virtualNodes = new TreeMap<Integer, String>();
public LZHash(List<String> realNodes) {
for(String node : realNodes) {
addNode(node);
}
}
private void addNode(String node) {
for(int i = 0; i < replcaNum; i ++) {
virtualNodes.put(md5(node + i).hashCode(), node);
}
realNodes.add(node);
}
private void removeNode(String node) {
for(int i = 0; i < replcaNum; i++) {
virtualNodes.remove(md5(node + i));
}
realNodes.remove(node);
}
public static String md5(String source) {
return Hashing.md5().newHasher().putString(source, Charsets.UTF_8).hash().toString();
}
public static String getRedisNode(String key) {
int hash = md5(key).hashCode();
if(virtualNodes.containsKey(hash)) {
return virtualNodes.get(hash);
}
SortedMap<Integer, String> temp = virtualNodes.tailMap(hash);
if(temp.isEmpty()) {
return virtualNodes.get(virtualNodes.firstKey());
}
return temp.get(temp.firstKey());
}
public static void main(String[] args) {
List<String> realNodes = new ArrayList<String>();
realNodes.add("192.168.96.220:6379");
realNodes.add("192.168.99.233:6379");
realNodes.add("192.168.99.60:6379");
LZHash h = new LZHash(realNodes);
String keyPrefix = "binova_shopcart_";
int node220 = 0;
int node233 = 0;
int node60 = 0;
for(int i = 0; i < 100000; i++) {
String key = keyPrefix + i;
String node = getRedisNode(key);
if(node.equals("192.168.96.220:6379")) {
node220 ++;
}if(node.equals("192.168.99.233:6379")) {
node233 ++;
}if(node.equals("192.168.99.60:6379")) {
node60 ++;
}
}
System.out.println("node220:" + node220);
System.out.println("node233:" + node233);
System.out.println("node60:" + node60);
}
}