第五周作业
发布于: 2020 年 07 月 08 日
用你熟悉的编程语言实现一致性 hash 算法。
编写测试用例测试这个算法,测试 100 万 KV 数据,10 个服务器节点的情况下,计算这些 KV 数据在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。
ServerNode.Java
public interface ServerNode { // 获取节点 String GetNode(String key);}
NodeList.Java
import java.util.LinkedList;import java.util.List;public class NodeList { public NodeList(){ for (int i=0; i< Servers.length;i++){ Nodes.add(Servers[i]); } } private static String[] Servers = { "192.168.0.10:1230", "192.168.1.10:1234", "192.168.2.10:1123", "192.168.3.10:1133", "192.168.4.10:1223", "192.168.5.10:1423", "192.168.6.10:1523", "192.168.7.10:1263", "192.168.8.10:1238", "192.168.9.10:1239", }; // 虚拟节点数 public static final int VIRTUAL_NODES = 100; private List<String> Nodes = new LinkedList<String>(); public List<String>GetNodes(){ return Nodes; }}
CoincidentHash.java
import org.springframework.util.StringUtils;import java.util.SortedMap;import java.util.TreeMap;public class CoincidentHash implements ServerNode{ private CoincidentHash(){ for (String str : nodeList.GetNodes()){ for(int i=0; i<NodeList.VIRTUAL_NODES; i++){ String virtualNodeName = str + "&&VN" + i; int hash = getHash(virtualNodeName); System.out.println("虚拟节点[" + virtualNodeName + "]被添加, hash值为" + hash); virtualNodes.put(hash, virtualNodeName); } } } // 真实节点 private NodeList nodeList = new NodeList(); // 虚拟节点,key表示虚拟节点的hash值,value表示虚拟节点的名称 private static SortedMap<Integer, String> virtualNodes = new TreeMap<Integer, String>(); @Override public String GetNode(String key) { // 得到该key的hash值 int hash = getHash(key); // 得到大于该Hash值的所有Map SortedMap<Integer, String> subMap = virtualNodes.tailMap(hash); String virtualNode; if(subMap.isEmpty()){ //如果没有比该key的hash值大的,则从第一个node开始 Integer i = virtualNodes.firstKey(); //返回对应的服务器 virtualNode = virtualNodes.get(i); }else{ //第一个Key就是顺时针过去离node最近的那个结点 Integer i = subMap.firstKey(); //返回对应的服务器 virtualNode = subMap.get(i); } //virtualNode虚拟节点名称要截取一下 if (!(StringUtils.isEmpty(virtualNode))){ return virtualNode.substring(0, virtualNode.indexOf("&&")); } return null; } private static class HashHolder{ private static CoincidentHash instance = new CoincidentHash(); } public static CoincidentHash getInstance(){ return HashHolder.instance; } // 使用FNV1_32_HASH算法计算服务器的Hash值 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; }}
Test.Java
import org.apache.commons.lang3.RandomStringUtils;//计算标准差 public static double StandardDiviation(double[] x) { int m=x.length; double sum=0; for(int i=0;i<m;i++){//求和 sum+=x[i]; } double dAve=sum/m;//求平均值 double dVar=0; for(int i=0;i<m;i++){//求方差 dVar+=(x[i]-dAve)*(x[i]-dAve); } //reture Math.sqrt(dVar/(m-1)); return Math.sqrt(dVar/m); } @Test void testCoincidentHash(){ HashMap<String,Integer> serverArrangement = new HashMap<>();// SortedMap<String,Integer> serverArrangement = new TreeMap<>(); NodeList nodeList = new NodeList(); for(String node : nodeList.GetNodes()) { serverArrangement.put(node,0); } String key; Integer count; String keynode; for (int i=0;i<1000000;i++){ key = RandomStringUtils.randomAlphanumeric(10); keynode = CoincidentHash.getInstance().GetNode(key); if (serverArrangement.containsKey(keynode)) { count = serverArrangement.get(keynode) + 1; serverArrangement.replace(keynode, count); } } Integer[] counts = new Integer[serverArrangement.size()]; serverArrangement.values().toArray(counts); double[] tmpCounts = new double[counts.length]; for (int i=0;i<counts.length;i++){ tmpCounts[i] = (double) counts[i]; } double sd = StandardDiviation(tmpCounts); System.out.println(String.format("10个节点,每个节点100个虚拟节点,100万个KV,分布标准差=%.2f",sd)); serverArrangement.forEach((k,v) -> System.out.println("server: "+ k+" keyNumber: "+v)); }
结果:
划线
评论
复制
发布于: 2020 年 07 月 08 日阅读数: 48
版权声明: 本文为 InfoQ 作者【王鑫龙】的原创文章。
原文链接:【http://xie.infoq.cn/article/5154dde895e274f7aaa9b0e02】。
本文遵守【CC BY-NC】协议,转载请保留原文出处及本版权声明。
王鑫龙
关注
还未添加个人签名 2018.02.04 加入
还未添加个人简介
评论