一致性hash演算法 java程式碼實現與測試
阿新 • • 發佈:2019-02-19
轉載:http://blog.csdn.net/pcceo1/article/details/51493934
寫了一個一致性hash的Java實現程式碼,演算法是用別人的,據說很好,然後自己做了一個測試,用執行緒池起了1000個執行緒,每個執行緒hash10000次,模擬一萬次資料hash,並將測試結果上傳。
- /**
- * 一致性hash程式碼
- *
- * @author shiguiming
- *
- * @param <T>
- */
- publicclass Shared<T> {
- // 真實節點對應的虛擬節點數量
-
privateint length = 100
- // 虛擬節點資訊
- private TreeMap<Long, T> virtualNodes;
- // 真實節點資訊
- private List<T> realNodes;
- public Shared(List<T> realNodes) {
- this.realNodes = realNodes;
- init();
- }
- public List<T> getReal() {
- return realNodes;
-
}
- /**
- * 初始化虛擬節點
- */
- privatevoid init() {
- virtualNodes = new TreeMap<Long, T>();
- 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 null
- Entry 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
- *
- */
- staticpublicclass Node {
- privateint name;
- privateint count = 0;
- public Node() {
- }
- public Node(int i) {
- this.name = i;
- }
- publicint getName() {
- return name;
- }
- publicvoid setName(int name) {
- this.name = name;
- }
- publicint getCount() {
- return count;
- }
- // 同步方法,防止併發
- synchronizedpublicvoid inc() {
- count++;
- }
- }
- /**
- * 測試方法
- *
- * @param args
- * @throws InterruptedException
- */
- publicstaticvoid main(String[] args) throws InterruptedException {
- List<Node> ndList = new ArrayList<Node>();
- int i = 0;
- while (true) {
- ndList.add(new Node(i));
- if (i++ == 9)
- break;
- }
- final Shared<Node> sh = new Shared<Node>(ndList);
- ExecutorService es = Executors.newCachedThreadPool();
- final CountDownLatch cdl = new CountDownLatch(1000);
- // 1000個執行緒
- for (int j = 0; j < 1000; j++) {
- es.execute(new Runnable() {
- @Override
- publicvoid run() {
- // Random rd = new Random(1100);
- for (int k = 0; k < 10000; k++) {
- sh.getNode(String.valueOf(Math.random())).inc();
- }
- cdl.countDown();
- }
- });
- }
- // 等待所有執行緒結束
- cdl.await();
- List<Node> nodeList = sh.getReal();
- for (Node node : nodeList) {
- System.out.println("node" + node.getName() + ":" + node.getCount());
- }
- }
- }
測試結果:
一共10,000,000次 hash,基本算是較均勻投遞到10個節點,有什麼問題大家交流~