连续性 一致性hash算法(Consistent hashing)( 二 )

virtualNodes = new TreeMap();/*** 虚拟节点的数目,这里写死,为了演示需要,一个真实结点对应5个虚拟节点*/private static final int VIRTUAL_NODES = 5;static{// 先把原始的服务器添加到真实结点列表中for (int i = 0; i < servers.length; i++)realNodes.add(servers[i]);// 再添加虚拟节点,遍历LinkedList使用foreach循环效率会比较高for (String str : realNodes){for (int i = 0; i < VIRTUAL_NODES; i++){String virtualNodeName = str + "&&VN" + String.valueOf(i);int hash = getHash(virtualNodeName);System.out.println("虚拟节点[" + virtualNodeName + "]被添加, hash值为" + hash);virtualNodes.put(hash, virtualNodeName);}}System.out.println();}/*** 使用FNV1_32_HASH算法计算服务器的Hash值,这里不使用重写hashCode的方法,最终效果没区别 */private static int getHash(String str){final int p = 16777619;int hash = (int)2166136261L;for (int i = 0; i < str.length(); i++)hash = (hash ^ str.charAt(i)) * p;hash += hash << 13;hash ^= hash >> 7;hash += hash << 3;hash ^= hash >> 17;hash += hash << 5;// 如果算出来的值为负数则取其绝对值if (hash < 0)hash = Math.abs(hash);return hash;}/*** 得到应当路由到的结点*/private static String getServer(String node){// 得到带路由的结点的Hash值int hash = getHash(node);// 得到大于该Hash值的所有MapSortedMap subMap = virtualNodes.tailMap(hash);// 第一个Key就是顺时针过去离node最近的那个结点Integer i = subMap.firstKey();// 返回对应的虚拟节点名称,这里字符串稍微截取一下String virtualNode = subMap.get(i);return virtualNode.substring(0, virtualNode.indexOf("&&"));}public static void main(String[] args){String[] nodes = {"127.0.0.1:1111", "221.226.0.1:2222", "10.211.0.1:3333"};for (int i = 0; i < nodes.length; i++)System.out.println("[" + nodes[i] + "]的hash值为" + getHash(nodes[i]) + ", 被路由到结点[" + getServer(nodes[i]) + "]");}}
另:
用线程池起了1000个线程,每个线程次,模拟一万次数据hash,并将测试结果上传 。
/*** 一致性hash代码* * @author shiguiming** @param */public class Shared {// 真实节点对应的虚拟节点数量private int length = 100;// 虚拟节点信息private TreeMap virtualNodes;// 真实节点信息private List realNodes;public Shared(List realNodes) {this.realNodes = realNodes;init();}public List getReal() {return realNodes;}/*** 初始化虚拟节点*/private void init() {virtualNodes = new TreeMap();for (int i = 0; i < realNodes.size(); i++) {for (int j = 0; j < length; j++) {virtualNodes.put(hash("aa" + i + j), realNodes.get(i));}}}/*** 获取一个结点* * @param key* @return*/@SuppressWarnings("unchecked")public T getNode(String key) {Long hashedKey = hash(key);// TODO judge nullEntry en = virtualNodes.ceilingEntry(hashedKey);if (en == null) {return (T) virtualNodes.firstEntry().getValue();}return (T) en.getValue();}/*** MurMurHash算法,是非加密HASH算法,性能很高,* 比传统的CRC32,MD5,SHA-1(这两个算法都是加密HASH算法,复杂度本身就很高,带来的性能上的损害也不可避免)* 等HASH算法要快很多,而且据说这个算法的碰撞率很低. http://murmurhash.googlepages.com/*/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);// for big-endian version, do this first:// finish.position(8-buf.remaining());finish.put(buf).rewind();h ^= finish.getLong();h *= m;}h ^= h >>> r;h *= m;h ^= h >>> r;buf.order(byteOrder);return h;}/*** 测试内部类* * @author shiguiming**/static public class Node {private int name;private int count = 0;public Node() {}public Node(int i) {this.name = i;}public int getName() {return name;}public void setName(int name) {this.name = name;}public int getCount() {return count;}// 同步方法,防止并发synchronized public void inc() {count++;}}/*** 测试方法* * @param args* @throws InterruptedException*/public static void main(String[] args) throws InterruptedException {List ndList = new ArrayList();int i = 0;while (true) {ndList.add(new Node(i));if (i++ == 9)break;}final Shared sh = new Shared(ndList);ExecutorService es = Executors.newCachedThreadPool();final CountDownLatch cdl = new CountDownLatch(1000);// 1000个线程for (int j = 0; j