一致性hash算法 java代码实现与测试

来源:互联网 发布:淘宝vip折扣价怎么设置 编辑:程序博客网 时间:2024/05/22 16:56

转载:http://blog.csdn.net/pcceo1/article/details/51493934

写了一个一致性hash的Java实现代码,算法是用别人的,据说很好,然后自己做了一个测试,用线程池起了1000个线程,每个线程hash10000次,模拟一万次数据hash,并将测试结果上传。

[java] view plain copy
  1. /** 
  2.  * 一致性hash代码 
  3.  *  
  4.  * @author shiguiming 
  5.  * 
  6.  * @param <T> 
  7.  */  
  8. public class Shared<T> {  
  9.   
  10.     // 真实节点对应的虚拟节点数量  
  11.     private int length = 100;  
  12.     // 虚拟节点信息  
  13.     private TreeMap<Long, T> virtualNodes;  
  14.     // 真实节点信息  
  15.     private List<T> realNodes;  
  16.   
  17.     public Shared(List<T> realNodes) {  
  18.         this.realNodes = realNodes;  
  19.         init();  
  20.     }  
  21.   
  22.     public List<T> getReal() {  
  23.         return realNodes;  
  24.     }  
  25.   
  26.     /** 
  27.      * 初始化虚拟节点 
  28.      */  
  29.     private void init() {  
  30.         virtualNodes = new TreeMap<Long, T>();  
  31.         for (int i = 0; i < realNodes.size(); i++) {  
  32.             for (int j = 0; j < length; j++) {  
  33.                 virtualNodes.put(hash("aa" + i + j), realNodes.get(i));  
  34.             }  
  35.         }  
  36.     }  
  37.   
  38.     /** 
  39.      * 获取一个结点 
  40.      *  
  41.      * @param key 
  42.      * @return 
  43.      */  
  44.     @SuppressWarnings("unchecked")  
  45.     public T getNode(String key) {  
  46.         Long hashedKey = hash(key);  
  47.         // TODO judge null  
  48.         Entry en = virtualNodes.ceilingEntry(hashedKey);  
  49.         if (en == null) {  
  50.             return (T) virtualNodes.firstEntry().getValue();  
  51.         }  
  52.         return (T) en.getValue();  
  53.     }  
  54.   
  55.     /** 
  56.      * MurMurHash算法,是非加密HASH算法,性能很高, 
  57.      * 比传统的CRC32,MD5,SHA-1(这两个算法都是加密HASH算法,复杂度本身就很高,带来的性能上的损害也不可避免) 
  58.      * 等HASH算法要快很多,而且据说这个算法的碰撞率很低. http://murmurhash.googlepages.com/ 
  59.      */  
  60.     private Long hash(String key) {  
  61.         ByteBuffer buf = ByteBuffer.wrap(key.getBytes());  
  62.         int seed = 0x1234ABCD;  
  63.   
  64.         ByteOrder byteOrder = buf.order();  
  65.         buf.order(ByteOrder.LITTLE_ENDIAN);  
  66.   
  67.         long m = 0xc6a4a7935bd1e995L;  
  68.         int r = 47;  
  69.   
  70.         long h = seed ^ (buf.remaining() * m);  
  71.   
  72.         long k;  
  73.         while (buf.remaining() >= 8) {  
  74.             k = buf.getLong();  
  75.   
  76.             k *= m;  
  77.             k ^= k >>> r;  
  78.             k *= m;  
  79.   
  80.             h ^= k;  
  81.             h *= m;  
  82.         }  
  83.   
  84.         if (buf.remaining() > 0) {  
  85.             ByteBuffer finish = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);  
  86.             // for big-endian version, do this first:  
  87.             // finish.position(8-buf.remaining());  
  88.             finish.put(buf).rewind();  
  89.             h ^= finish.getLong();  
  90.             h *= m;  
  91.         }  
  92.   
  93.         h ^= h >>> r;  
  94.         h *= m;  
  95.         h ^= h >>> r;  
  96.   
  97.         buf.order(byteOrder);  
  98.         return h;  
  99.     }  
  100.   
  101.     /** 
  102.      * 测试内部类 
  103.      *  
  104.      * @author shiguiming 
  105.      * 
  106.      */  
  107.     static public class Node {  
  108.         private int name;  
  109.         private int count = 0;  
  110.   
  111.         public Node() {  
  112.   
  113.         }  
  114.   
  115.         public Node(int i) {  
  116.             this.name = i;  
  117.         }  
  118.   
  119.         public int getName() {  
  120.             return name;  
  121.         }  
  122.   
  123.         public void setName(int name) {  
  124.             this.name = name;  
  125.         }  
  126.   
  127.         public int getCount() {  
  128.             return count;  
  129.         }  
  130.   
  131.         // 同步方法,防止并发  
  132.         synchronized public void inc() {  
  133.             count++;  
  134.         }  
  135.   
  136.     }  
  137.   
  138.     /** 
  139.      * 测试方法 
  140.      *  
  141.      * @param args 
  142.      * @throws InterruptedException 
  143.      */  
  144.     public static void main(String[] args) throws InterruptedException {  
  145.         List<Node> ndList = new ArrayList<Node>();  
  146.         int i = 0;  
  147.         while (true) {  
  148.             ndList.add(new Node(i));  
  149.             if (i++ == 9)  
  150.                 break;  
  151.         }  
  152.   
  153.         final Shared<Node> sh = new Shared<Node>(ndList);  
  154.         ExecutorService es = Executors.newCachedThreadPool();  
  155.         final CountDownLatch cdl = new CountDownLatch(1000);  
  156.         // 1000个线程  
  157.         for (int j = 0; j < 1000; j++) {  
  158.             es.execute(new Runnable() {  
  159.   
  160.                 @Override  
  161.                 public void run() {  
  162.                     // Random rd = new Random(1100);  
  163.                     for (int k = 0; k < 10000; k++) {  
  164.                         sh.getNode(String.valueOf(Math.random())).inc();  
  165.                     }  
  166.                     cdl.countDown();  
  167.                 }  
  168.             });  
  169.         }  
  170.   
  171.         // 等待所有线程结束  
  172.         cdl.await();  
  173.         List<Node> nodeList = sh.getReal();  
  174.         for (Node node : nodeList) {  
  175.             System.out.println("node" + node.getName() + ":" + node.getCount());  
  176.         }  
  177.   
  178.     }  
  179. }  

测试结果:


一共10,000,000次 hash,基本算是较均匀投递到10个节点,有什么问题大家交流~


阅读全文
0 0
原创粉丝点击