您的位置:首页 > 其它

一致性hash 算法

2014-08-17 14:46 357 查看
一、hash值function

package constains;

import java.security.MessageDigest;

import java.security.NoSuchAlgorithmException;

public class HashFunction {

private MessageDigest md5 = null;

//使用md5加密
public long hash(String key) {
if (md5 == null) {
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("no md5 algorythm found");
}
}
md5.reset();
md5.update(key.getBytes());
byte[] bKey = md5.digest();
long res = ((long) (bKey[3] & 0xFF) << 24)
| ((long) (bKey[2] & 0xFF) << 16)
| ((long) (bKey[1] & 0xFF) << 8) | (long) (bKey[0] & 0xFF);
return res & 0xffffffffL;
}

}


二、算法function

package constains;

import java.util.Collection;
import java.util.SortedMap;
import java.util.TreeMap;

public class ConsistentHash<T> {

private final HashFunction hashFunction;

private final int numberOfReplicas; // 虚拟节点

private final SortedMap<Long, T> circle = new TreeMap<Long, T>(); // 用来存储虚拟节点hash值

/**
* <默认构造函数>
* hashFunction 哈希算法   numberOfReplicas虚拟节点个数  nodes实际节点集合(set)
*/
public ConsistentHash(HashFunction hashFunction, int numberOfReplicas,
Collection<T> nodes) {

this.hashFunction = hashFunction;

this.numberOfReplicas = numberOfReplicas;

//在构造函数中执行  将实际节点数 虚拟
for (T node : nodes) {

add(node);

}
}

/**
*
* 添加 numberOfReplicas 个虚拟节点到hash环中,并映射到真实节点
*
* @param node真实节点
*
* @return
*/
public void add(T node) {

//根基每个节点要虚拟出的个数循环,使用 节点名字加数字 求hash值 用来标示
for (int i = 0; i < numberOfReplicas; i++) {

circle.put(hashFunction.hash(node.toString() + i), node);

}

}

/**
*
* 删除hash环中真实节点对应的虚拟节点
*
* @param node真实节点
*
* @return
*/
public void remove(T node) {

//删除的时候 将 该节点所有对应的虚拟节点全部删除
for (int i = 0; i < numberOfReplicas; i++) {

circle.remove(hashFunction.hash(node.toString() + i));

}

}

/**
*
* 获得一个最近的顺时针节点
*
* @param key
*            为给定键取Hash,取得顺时针方向上最近的一个虚拟节点对应的实际节点
*
* @return
*/
//该方法会根基访问主机的ip去hash环上取连接,如果不存在取顺时针第一个,保证均衡
public T get(Object key) {

if (circle.isEmpty()) {

return null;

}

long hash = hashFunction.hash((String) key);

if (!circle.containsKey(hash)) {

SortedMap<Long, T> tailMap = circle.tailMap(hash); // //返回此映射的部分视图,其键大于等于hash值

//获取根据hash值获取到的第一个key值对应的value,如果没有找到,取hash环的第一个节点
hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
}

return circle.get(hash);

}

/**
*
* 返回虚拟节点个数
*
*
* @return
*/

public long getSize() {

return circle.size();

}

}


三、调用main

package constains;

import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

public class MainApp {
public static void main(String[] args) {
Set<String> nodes = new HashSet<String>();
nodes.add("A");
nodes.add("B");
nodes.add("C");
ConsistentHash<String> consistentHash = new ConsistentHash<String>(
new HashFunction(), 5, nodes);
consistentHash.add("D");
int count1 = 0;
int count2 = 0;
int count3 = 0;
int count4 = 0;
int count5 = 0;
for(int i = 0; i <200000;i++){
UUID uuid = UUID.randomUUID();
String str = consistentHash.get(uuid.toString());
if("A".equals(str)){
count1++;
}else if("B".equals(str)){
count2++;
}else if("C".equals(str)){
count3++;
}else if("D".equals(str)){
count4++;
}else {
count5++;
}
}
System.out.println("A>>>命中次数:"+count1+">>>命中率:"+count1/200000.0*100+"%");
System.out.println("B>>>命中次数:"+count2+">>>命中率:"+count2/200000.0*100+"%");
System.out.println("C>>>命中次数:"+count3+">>>命中率:"+count3/200000.0*100+"%");
System.out.println("D>>>命中次数:"+count4+">>>命中率:"+count4/200000.0*100+"%");
System.out.println("没有命中次数 :"+count5+">>>概率:"+count5/200000.0*100+"%");

}

}
引用 http://blog.csdn.net/yq76034150/article/details/6776044
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: