`
godandghost
  • 浏览: 33459 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

一致性hash算法

阅读更多
public class LoadBalanceManager {

	private static TreeMap<Long, Node> nodes; // 虚拟节点到真实节点的映射
	private static TreeMap<Long, Node> treeKey; // key到真实节点的映射
	private static final int NODE_NUM = 10; // 每个机器节点关联的虚拟节点个数

	/**
	 * 初始化方法,将作为节点的机器List传入作为参数
	 * @param nodeList
	 */
	public LoadBalanceManager(List<Node> nodeList) {
		nodes = new TreeMap<Long, Node>();
		treeKey = new TreeMap<Long, Node>();
		for (Node node : nodeList) {
			for (int n = 0; n < NODE_NUM; n++) {
				// 一个真实机器节点关联NODE_NUM个虚拟节点
				nodes.put(hash("SHARD-" + node.getIp() + "-NODE-" + n), node);
			}
		}
	}
	
	/**
	 * 映射key到真实节点
	 * @param ip
	 */
	public void loadBalance(String ip) {
		SortedMap<Long, Node> tail = nodes.tailMap(hash(ip)); // 沿环的顺时针找到一个虚拟节点
		if (tail.size() == 0) {
			// 如果此ip的hash值比任何一个节点的值都大,则取第一个节点
			Node first = nodes.firstEntry().getValue();
			treeKey.put(hash(ip), first);
			System.out.println(ip + "(hash: " + hash(ip) + ")连接到主机->" + first);
			return;
		}
		treeKey.put(hash(ip), tail.get(tail.firstKey()));
		System.out.println(ip + "(hash: " + hash(ip) + ")连接到主机->"
				+ tail.get(tail.firstKey()));
	}

	/**
	 * 增加一个主机
	 * 
	 * @param node
	 */
	public void addNode(Node node) {
		System.out.println("增加主机" + node + "的变化:");
		for (int n = 0; n < NODE_NUM; n++) {
			Long key = hash("SHARD-" + node.getIp() + "-NODE-" + n);
			addS(key, node);
		}
	}

	/**
	 * 删除真实节点
	 * 
	 * @param node
	 */
	public void deleteNode(Node node) {
		if (node == null) {
			return;
		}
		System.out.println("删除主机" + node + "的变化:");
		for (int i = 0; i < NODE_NUM; i++) {
			// 定位s节点的第i的虚拟节点的位置
			Long key = hash("SHARD-" + node.getIp() + "-NODE-" + i);
			SortedMap<Long, Node> tail = nodes.tailMap(key);
			SortedMap<Long, Node> head = nodes.headMap(key);
			Long begin = 0L;
			Long end = 0L;

			SortedMap<Long, Node> between;
			if (head.size() == 0) {
				between = treeKey.headMap(nodes.firstKey());
				end = tail.firstKey();
				tail.remove(end);
//				nodes.remove(end);// 从nodes中删除s节点的第i个虚拟节点
			} else {
				begin = head.lastKey();
				end = tail.firstKey();
				tail.remove(end);
				between = treeKey.subMap(begin, end);// 在s节点的第i个虚拟节点的所有key的集合
			}
			for (Iterator<Long> it = between.keySet().iterator(); it.hasNext();) {
				Long lo = it.next();
				treeKey.put(lo, tail.get(tail.firstKey()));
				System.out.println("hash(" + lo + ")改变到->"
						+ tail.get(tail.firstKey()));
			}
		}
	}

	/**
	 * 添加一个虚拟节点进环形结构,lg为虚拟节点的hash值
	 * 
	 * @param hashKey
	 * @param node
	 */
	private void addS(Long hashKey, Node node) {
		SortedMap<Long, Node> tail = nodes.tailMap(hashKey);
		SortedMap<Long, Node> head = nodes.headMap(hashKey);
		Long begin = 0L;
		SortedMap<Long, Node> between;
		if (head.size() == 0) {
			between = treeKey.headMap(hashKey);
		} else {
			begin = head.lastKey();
			between = treeKey.subMap(begin, hashKey);
		}
		nodes.put(hashKey, node);
		for (Iterator<Long> it = between.keySet().iterator(); it.hasNext();) {
			Long lo = it.next();
			treeKey.put(lo, nodes.get(hashKey));
			System.out.println("hash(" + lo + ")改变到->"
					+ tail.get(tail.firstKey()));
		}
	}

	/**
	 * MurMurHash算法,是非加密HASH算法,性能很高,
	 * 比传统的CRC32,MD5,SHA-1(这两个算法都是加密HASH算法,复杂度本身就很高,带来的性能上的损害也不可避免)
	 * 等HASH算法要快很多,而且据说这个算法的碰撞率很低.
	 */
	private Long hash(String key) {
		ByteBuffer buf = ByteBuffer.wrap(key.getBytes());
		int seed = 0x1234ABCD;

		ByteOrder byteOrder = buf.order();
		buf.order(ByteOrder.LITTLE_ENDIAN);

		long m = 0xc6a4a7935bd1e995L;
		int r = 47;

		long h = seed ^ (buf.remaining() * m);

		long k;
		while (buf.remaining() >= 8) {
			k = buf.getLong();

			k *= m;
			k ^= k >>> r;
			k *= m;

			h ^= k;
			h *= m;
		}

		if (buf.remaining() > 0) {
			ByteBuffer finish = ByteBuffer.allocate(8).order(
					ByteOrder.LITTLE_ENDIAN);
			finish.put(buf).rewind();
			h ^= finish.getLong();
			h *= m;
		}

		h ^= h >>> r;
		h *= m;
		h ^= h >>> r;

		buf.order(byteOrder);
		return h;
	}
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics