架构师训练营 - 第五周作业
发布于: 2020 年 10 月 25 日
用你熟悉的编程语言实现一致性 hash 算法。
public class Node { private Node(){} public Node(String name,String ip){ this.name=name; this.ip=ip; } private String name; private String ip; public long getCount() { return count.get(); } public AtomicLong count=new AtomicLong(0); public void incr(){ count.incrementAndGet(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip; }}
public class NodePool { // 实例节点列表 private List<Node> nodeList=null; // 虚拟节点列表 private TreeMap<Integer,Node> hashMaps=new TreeMap<>(); // 实例节点转为多少个虚拟节点 private int virtualNum; private NodePool(){} public NodePool(List<Node> nodeList,int virtualNum){ this.nodeList=nodeList; this.virtualNum=virtualNum; for(Node node:nodeList){ for (int i = 0; i <virtualNum ; i++) { int hash=hashCode(node.getName()+"-"+i); hashMaps.put(hash,node); } } } public Node getNodeObj(int key){ Map.Entry<Integer, Node> nodeEntry = getHashMaps().ceilingEntry(key); if(nodeEntry==null)nodeEntry=getHashMaps().firstEntry(); return nodeEntry.getValue(); } public static int hashCode(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);// } //System.out.println(hash); return hash; } public List<Node> getNodeList() { return nodeList; } public TreeMap<Integer, Node> getHashMaps() { return hashMaps; } public int getVirtualNum() { return virtualNum; }}
编写测试用例测试这个算法,测试 100 万 KV 数据,10 个服务器节点的情况下,计算这些 KV 数据在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。
public class HashDemo { public static void main(String[] args) { List<Node> nodeList=new ArrayList<>(); nodeList.add(new Node("node01","192.168.0.11")); nodeList.add(new Node("node02","192.168.0.12")); nodeList.add(new Node("node03","192.168.0.13")); nodeList.add(new Node("node04","192.168.0.14")); nodeList.add(new Node("node05","192.168.0.15")); nodeList.add(new Node("node06","192.168.0.16")); nodeList.add(new Node("node07","192.168.0.17")); nodeList.add(new Node("node08","192.168.0.18")); nodeList.add(new Node("node09","192.168.0.19")); nodeList.add(new Node("node10","192.168.0.20")); NodePool nodePool1 = new NodePool(nodeList,50); NodePool nodePool2 = new NodePool(nodeList,100); NodePool nodePool3 = new NodePool(nodeList,150); NodePool nodePool4 = new NodePool(nodeList,200); NodePool nodePool5 = new NodePool(nodeList,250); HashDemo hashDemo = new HashDemo(); hashDemo.display(nodePool1); hashDemo.display(nodePool2); hashDemo.display(nodePool3); hashDemo.display(nodePool4); hashDemo.display(nodePool5); } public void display(NodePool nodePool){ Integer nKey; for (int i = 0; i <1000000 ; i++) { nKey=NodePool.hashCode("key"+i); Node nodeObj = nodePool.getNodeObj(nKey); nodeObj.incr(); } /* 计算平方差 */ List<Double> tmpList1=new ArrayList(); for(Node node:nodePool.getNodeList()){// System.out.println("nodeName="+node.getName()+",count="+node.getCount()); tmpList1.add(Double.parseDouble(node.getCount()+"")); } System.out.println(nodePool.getVirtualNum()+"个虚拟节点,平方差为:"+getStandardDiviation(tmpList1)); } public double getStandardDiviation(List<Double> x) { int m = x.size(); double sum = 0; for (int i = 0; i < m; i++) {// 求和 sum += x.get(i); } double dAve = sum / m;// 求平均值 double dVar = 0; for (int i = 0; i < m; i++) {// 求方差 dVar += (x.get(i) - dAve) * (x.get(i) - dAve); } return Math.sqrt(dVar / m); }}
50个虚拟节点,平方差为:13551.925449913013100个虚拟节点,平方差为:18109.49825920089150个虚拟节点,平方差为:20364.833738579848200个虚拟节点,平方差为:24623.291112278228250个虚拟节点,平方差为:27584.167400884155
划线
评论
复制
发布于: 2020 年 10 月 25 日阅读数: 31
一个节点
关注
还未添加个人签名 2020.07.27 加入
还未添加个人简介
评论