package com.zqh.cache; /** * Created by zqhxuyuan on 15-3-23. */ import java.util.SortedMap; import java.util.TreeMap; import org.apache.commons.codec.digest.DigestUtils; /** * http://www.sccoder.com/algorithm/consistenthashing.html * http://weblogs.java.net/blog/2007/11/27/consistent-hashing * 利用JDK中TreeMap的排序功能进行hash环的映射 * @author 亦凡 一致性hash算法的实现 */ public class ConsistencyHash<T> { /** * 存储服务器信息,key为服务器的hash值,TreeMap根据key进行了排序,便于查找映射节点 * @uml.property name="circle" * @uml.associationEnd multiplicity="(0 -1)" ordering="true" elementType="java.lang.Long" qualifier="valueOf:java.lang.Long java.lang.Object" */ private TreeMap<Long, T> circle = null; /** * @uml.property name="numberOfReplicas" */ private int numberOfReplicas; public ConsistencyHash() { circle = new TreeMap<Long, T>(); } public ConsistencyHash(T[] servers) { circle = new TreeMap<Long, T>(); for (T server : servers) { addServer(server); } } public ConsistencyHash(T[] servers, int numberOfReplicas) { circle = new TreeMap<Long, T>(); this.numberOfReplicas = numberOfReplicas; for (T server : servers) { addServer(server); } } /** * 映射服务器到hash环上 */ public void addServer(T server) { for (int i = 0; i < numberOfReplicas; i++) { circle.put(hash(server.toString() + i), server); } } /** * 从hash环上移除服务器 */ public void removeServer(T server) { for (int i = 0; i < numberOfReplicas; i++) { circle.remove(hash(server.toString() + i)); } } /** * 根据key的hash值在hash环上的映射查找key映射的服务器 * * @param keyHash * @return */ public T getServerNode(Long keyHash) { if (circle == null || circle.isEmpty()) { return null; } SortedMap<Long, T> tailMap = circle.tailMap(keyHash); if (tailMap.isEmpty()) { keyHash = circle.firstKey(); } else { keyHash = tailMap.firstKey(); } return circle.get(keyHash); } /** * 打印server节点映射顺序 */ public void printServerMapOrder() { System.out.println(circle); } /** * 计算hash * * @param obj * @return */ public static long hash(Object obj) { byte[] data = DigestUtils.md5(obj.toString().getBytes()); return data[0] | ((long) data[1] << 8) | ((long) data[2] << 16) | ((long) data[3] << 24) | ((long) data[4] << 32) | ((long) data[5] << 40) | ((long) data[6] << 48) | ((long) data[7] << 56); } /** * byte数组转化为long数组 * * @param byteArray * @return */ public static long byteToLong(byte[] byteArray) { return Long.parseLong(new String(byteArray)); } public static void main(String[] args) { String[] servers = new String[] { "Server 1:192.168.1.1", "Server 2:192.168.1.2", "Server 3:192.168.1.3", "Server 4:192.168.1.4", "Server 5:192.168.1.5" }; ConsistencyHash<String> consHash = new ConsistencyHash<String>(servers); System.out.println("服务器映射信息:"); consHash.printServerMapOrder(); System.out.println("数据映射信息:"); showDataMap(consHash); // 移除server2 consHash.removeServer(servers[2]); System.out.println("移除server 3后数据映射信息:"); showDataMap(consHash); } public static void showDataMap(ConsistencyHash<String> consHash) { for (int i = 0; i < 5; i++) { System.out.println("Data" + i + " mapped at " + consHash.getServerNode(ConsistencyHash.hash("Data" + i))); } } }