一致性哈希实现
发布于: 2020 年 07 月 08 日
实现一致性哈希的要点:
有一个很多slot的环
每个服务器有N个虚拟节点,分布到环上,一个虚拟节点对应一个slot
存储数据时,key的哈希值,没顺时针方向找到最近的slot(包括相等)对应的节点进行存储
哈希函数要使计算的哈希值尽量均匀分布
1、取哈希值接口
public interface IHashService { int hash(String key);}
2、取哈希值实现
import java.nio.ByteBuffer;import java.nio.ByteOrder;public class HashService implements IHashService { @Override public int 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; return (int)(Math.abs(h) % Integer.MAX_VALUE); }}
3、服务器结点
public class Node { private String ip; private int port; public Node(String ip, int port) { this.ip = ip; this.port = port; } @Override public String toString() { return "Node{" + "ip='" + ip + '\'' + ", port=" + port + '}'; }}
4、一致性哈希
import java.util.SortedMap;import java.util.TreeMap;public class ConsistentHash<T> { /** * 每台服务器的slot数量 */ private int slotNumberPerServer; /** * 一致性哈希环 */ private SortedMap<Integer, T> hashCircle = new TreeMap<Integer, T>(); /** * 哈希算法服务 */ private IHashService hashService; public ConsistentHash(int slotNumberPerServer, IHashService hashService) { this.slotNumberPerServer = slotNumberPerServer; this.hashService = hashService; } public void addNode(T node) { for (int i = 0; i < slotNumberPerServer; i++) { hashCircle.put(hashService.hash(node.toString() + i), node); } } public void removeNode(T node) { for (int i = 0; i < slotNumberPerServer; i++) { hashCircle.remove(hashService.hash(node.toString() + i)); } } public T getNodeByKey(String key) { if (hashCircle.isEmpty()) { return null; } int hashCode = hashService.hash(key); if (!hashCircle.containsKey(hashCode)) { SortedMap<Integer, T> tailMap = hashCircle.tailMap(hashCode); hashCode = tailMap.isEmpty() ? hashCircle.firstKey() : tailMap.firstKey(); } return hashCircle.get(hashCode); } public static void main(String[] args) { System.out.println(-4 >> 2); System.out.println(-4 >>> 2); }}
5、调用及测试
import java.util.HashMap;import java.util.Map;import java.util.UUID;public class Client { public static void main(String[] args) { IHashService hashService = new HashService(); ConsistentHash<Node> nodeConsistentHash = new ConsistentHash<>(100, hashService); Map<Node, Integer> hitMap = new HashMap<>(); int countNode = 10; for (int i = 0; i < countNode; i++) { Node node = new Node("192.168.1." + i, 8080); nodeConsistentHash.addNode(node); System.out.println(node.hashCode()); hitMap.put(node, 0); } System.out.println("--------------------------------------------------------"); long startTime = System.currentTimeMillis(); int countKV = 1000000; for (int i = 0; i < countKV; i++) { String uuid = UUID.randomUUID().toString(); Node node = nodeConsistentHash.getNodeByKey(uuid); int count = hitMap.get(node); hitMap.put(node, ++count); } for (Map.Entry<Node, Integer> entry : hitMap.entrySet()) { System.out.println(entry.toString()); } System.out.println("--------------------------------------------------------"); long spentTime = System.currentTimeMillis() - startTime; System.out.println(String.format("spent %s ms", spentTime)); int averageHit = countKV / countNode; double temp = hitMap.values().stream().map(value -> Math.pow((value - averageHit), 2)).reduce(0.0, (s, e) -> s = s + e); double standardDeviation = Math.sqrt(temp/countNode); System.out.println("standardDeviation: " + standardDeviation); }}
划线
评论
复制
发布于: 2020 年 07 月 08 日 阅读数: 54
娄江国
关注
还未添加个人签名 2017.11.10 加入
还未添加个人简介
评论