一致性hash 算法


一、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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值