架构师训练营 - 第 5 周作业
发布于: 2020 年 07 月 09 日
作业一:
用你熟悉的编程语言实现一致性 hash 算法。
编写测试用例测试这个算法,测试 100 万 KV 数据,10 个服务器节点的情况下,计算这些 KV 数据在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。
// 算法的主要实现类package architect;import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;import java.math.BigDecimal;import java.math.RoundingMode;import java.util.*;public class ConsistentHashWithVirtualNode { /** * 服务器节点个数 */ private Integer serverNodeCount; /** * 每个服务器的虚拟节点的个数 */ private Integer virtualNodeCount; /** * 服务器节点名称 */ private String serverNodeName; /** * 虚拟节点名称 */ private String virtualNodeName; public ConsistentHashWithVirtualNode(Integer serverNodeCount, Integer virtualNodeCount, String serverNodeName, String virtualName) { this.serverNodeCount = serverNodeCount; this.virtualNodeCount = virtualNodeCount; this.serverNodeName = serverNodeName; this.virtualNodeName = virtualName; } public SortedMap<Integer, String> initNodes(){ SortedMap<Integer, String> result = new TreeMap<>(); for (int i = 0; i < serverNodeCount; i++) { for (int j = 0; j < virtualNodeCount; j++) { String node = serverNodeName + i + virtualNodeName + j; int hash = HashUtils.getHash(node); result.put(hash, node); } } return result; } public BigDecimal calculateStandardDeviation(Collection<Integer> dataList) { SortedMap<Integer, String> serverNodes = this.initNodes(); Map<String,Integer> countMap = new HashMap<>(); for(Integer data : dataList){ String hitServerName = HitServerUtils.hitServer(data, serverNodes, virtualNodeName); HitServerUtils.countHit(hitServerName,countMap); } return calculateServerNodeStandardDeviation(countMap); } private BigDecimal calculateServerNodeStandardDeviation(Map<String,Integer> map) { double[] values = new double[serverNodeCount+1]; int i = 0; for (Map.Entry<String, Integer> entry: map.entrySet()) { values[i++] = entry.getValue(); System.out.println(String.format("虚拟节点数量为 %s,服务器 %s 的命中次数为" + entry.getValue() , virtualNodeCount, entry.getKey())); } StandardDeviation standardDeviation = new StandardDeviation(); return new BigDecimal(standardDeviation.evaluate(values)).setScale(0, RoundingMode.HALF_UP); }}
package architect;// HashCode计算类public class HashUtils { /** * 使用FNV1_32_HASH算法计算服务器的Hash值 */ public 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; }}
// 计算服务器的命中package architect;import java.util.Map;import java.util.SortedMap;public class HitServerUtils { public static String hitServer(Integer node, SortedMap<Integer, String> nodeMap, String virtualNodeName){ // 得到大于该Hash值的所有Map SortedMap<Integer, String> subMap = nodeMap.tailMap(node); // 第一个Key就是顺时针过去离node最近的那个结点 if(subMap.size()>0){ Integer i = subMap.firstKey(); // 返回对应的虚拟节点名称,这里字符串稍微截取一下 String virtualNode = subMap.get(i); return virtualNode.substring(0, virtualNode.indexOf(virtualNodeName)); } return nodeMap.get(nodeMap.firstKey()).substring(0, nodeMap.get(nodeMap.firstKey()).indexOf(virtualNodeName)); } public static void countHit(String node, Map<String, Integer> map){ if(map.containsKey(node)){ map.put(node,map.get(node)+1); return; } map.put(node,1); }}
// 单元测试类package architect;import junit.framework.TestCase;import org.junit.Test;import java.math.BigDecimal;import java.util.*;public class ConsistentHashWithVirtualCodeTest extends TestCase { /** * 基于虚拟节点的一致性hash算法 */ private ConsistentHashWithVirtualNode consistentHashWithVirtualNode; /** * 服务器节点个数 */ private int serverNodeCount = 10; /** * 待查找命中缓存数据个数 */ private int keyNumber = 1000000; /** * 待查找命中缓存数据hashCode清单 */ private Collection<Integer> dataList; /** * 服务器节点名称 */ private String serverNodeName = "serverNode"; /** * 虚拟节点名称 */ private String virtualNodeName = "&&virtual"; /** * 待测试每个服务器的虚拟节点的个数清单 */ private List<Integer> virtualNodeNumbers = Arrays.asList(1, 5, 100, 120, 140, 150, 180, 200, 250, 300, 400, 500, 1000, 1500, 2000, 2500); @Override public void setUp() { this.dataList = this.initDataToHit(); System.out.println("总数据个数为 " + this.dataList.size()); } /** * 服务器节点在设置不同虚拟节点个数下缓存命中的次数的标准差测试 */ @Test public void testServerNodeTitTimesStandardDeviationByVirtualNode() { SortedMap<Integer, BigDecimal> standardDeviations = new TreeMap<>(); virtualNodeNumbers.forEach(virtualNodeNumber -> { consistentHashWithVirtualNode = new ConsistentHashWithVirtualNode(serverNodeCount, virtualNodeNumber, serverNodeName, virtualNodeName); BigDecimal standardDeviation = consistentHashWithVirtualNode.calculateStandardDeviation(dataList); standardDeviations.put(virtualNodeNumber, standardDeviation); }); standardDeviations.entrySet().forEach(standardDeviation -> { System.out.println(String.format("虚拟节点数量为 %s,标准差为:%s", standardDeviation.getKey(), standardDeviation.getValue())); }); } /** * 初始化待缓存查找命中数据hashCode集合 * * @return hashCode集合 */ private Collection<Integer> initDataToHit() { Collection<Integer> result = new ArrayList<>(); for (int i = 0; i < keyNumber; i++) { int value = HashCodeUtils.getHash(UUID.randomUUID().toString()); result.add(value); } return result; }}
结果:
总数据个数为 1000000虚拟节点数量为 1,服务器 serverNode9 的命中次数为97187虚拟节点数量为 1,服务器 serverNode8 的命中次数为78086虚拟节点数量为 1,服务器 serverNode7 的命中次数为85674虚拟节点数量为 1,服务器 serverNode6 的命中次数为29623虚拟节点数量为 1,服务器 serverNode5 的命中次数为89130虚拟节点数量为 1,服务器 serverNode4 的命中次数为182166虚拟节点数量为 1,服务器 serverNode3 的命中次数为9496虚拟节点数量为 1,服务器 serverNode2 的命中次数为131325虚拟节点数量为 1,服务器 serverNode1 的命中次数为255595虚拟节点数量为 1,服务器 serverNode0 的命中次数为41718虚拟节点数量为 5,服务器 serverNode9 的命中次数为73578虚拟节点数量为 5,服务器 serverNode8 的命中次数为180238虚拟节点数量为 5,服务器 serverNode7 的命中次数为41220虚拟节点数量为 5,服务器 serverNode6 的命中次数为128081虚拟节点数量为 5,服务器 serverNode5 的命中次数为86920虚拟节点数量为 5,服务器 serverNode4 的命中次数为74617虚拟节点数量为 5,服务器 serverNode3 的命中次数为68683虚拟节点数量为 5,服务器 serverNode2 的命中次数为141864虚拟节点数量为 5,服务器 serverNode1 的命中次数为112912虚拟节点数量为 5,服务器 serverNode0 的命中次数为91887虚拟节点数量为 100,服务器 serverNode9 的命中次数为106150虚拟节点数量为 100,服务器 serverNode8 的命中次数为91360虚拟节点数量为 100,服务器 serverNode7 的命中次数为101192虚拟节点数量为 100,服务器 serverNode6 的命中次数为99490虚拟节点数量为 100,服务器 serverNode5 的命中次数为111914虚拟节点数量为 100,服务器 serverNode4 的命中次数为90069虚拟节点数量为 100,服务器 serverNode3 的命中次数为98016虚拟节点数量为 100,服务器 serverNode2 的命中次数为101417虚拟节点数量为 100,服务器 serverNode1 的命中次数为95026虚拟节点数量为 100,服务器 serverNode0 的命中次数为105366虚拟节点数量为 120,服务器 serverNode9 的命中次数为102905虚拟节点数量为 120,服务器 serverNode8 的命中次数为91757虚拟节点数量为 120,服务器 serverNode7 的命中次数为107976虚拟节点数量为 120,服务器 serverNode6 的命中次数为109105虚拟节点数量为 120,服务器 serverNode5 的命中次数为111018虚拟节点数量为 120,服务器 serverNode4 的命中次数为93980虚拟节点数量为 120,服务器 serverNode3 的命中次数为94215虚拟节点数量为 120,服务器 serverNode2 的命中次数为92237虚拟节点数量为 120,服务器 serverNode1 的命中次数为92362虚拟节点数量为 120,服务器 serverNode0 的命中次数为104445虚拟节点数量为 140,服务器 serverNode9 的命中次数为109771虚拟节点数量为 140,服务器 serverNode8 的命中次数为96680虚拟节点数量为 140,服务器 serverNode7 的命中次数为104084虚拟节点数量为 140,服务器 serverNode6 的命中次数为104986虚拟节点数量为 140,服务器 serverNode5 的命中次数为112695虚拟节点数量为 140,服务器 serverNode4 的命中次数为91172虚拟节点数量为 140,服务器 serverNode3 的命中次数为91529虚拟节点数量为 140,服务器 serverNode2 的命中次数为91174虚拟节点数量为 140,服务器 serverNode1 的命中次数为96932虚拟节点数量为 140,服务器 serverNode0 的命中次数为100977虚拟节点数量为 150,服务器 serverNode9 的命中次数为102331虚拟节点数量为 150,服务器 serverNode8 的命中次数为95192虚拟节点数量为 150,服务器 serverNode7 的命中次数为106368虚拟节点数量为 150,服务器 serverNode6 的命中次数为104536虚拟节点数量为 150,服务器 serverNode5 的命中次数为108816虚拟节点数量为 150,服务器 serverNode4 的命中次数为93751虚拟节点数量为 150,服务器 serverNode3 的命中次数为98255虚拟节点数量为 150,服务器 serverNode2 的命中次数为91523虚拟节点数量为 150,服务器 serverNode1 的命中次数为92389虚拟节点数量为 150,服务器 serverNode0 的命中次数为106839虚拟节点数量为 180,服务器 serverNode9 的命中次数为95511虚拟节点数量为 180,服务器 serverNode8 的命中次数为97311虚拟节点数量为 180,服务器 serverNode7 的命中次数为105246虚拟节点数量为 180,服务器 serverNode6 的命中次数为103885虚拟节点数量为 180,服务器 serverNode5 的命中次数为101063虚拟节点数量为 180,服务器 serverNode4 的命中次数为99486虚拟节点数量为 180,服务器 serverNode3 的命中次数为105489虚拟节点数量为 180,服务器 serverNode2 的命中次数为99242虚拟节点数量为 180,服务器 serverNode1 的命中次数为89041虚拟节点数量为 180,服务器 serverNode0 的命中次数为103726虚拟节点数量为 200,服务器 serverNode9 的命中次数为100093虚拟节点数量为 200,服务器 serverNode8 的命中次数为97431虚拟节点数量为 200,服务器 serverNode7 的命中次数为103665虚拟节点数量为 200,服务器 serverNode6 的命中次数为109936虚拟节点数量为 200,服务器 serverNode5 的命中次数为103993虚拟节点数量为 200,服务器 serverNode4 的命中次数为94820虚拟节点数量为 200,服务器 serverNode3 的命中次数为101720虚拟节点数量为 200,服务器 serverNode2 的命中次数为92533虚拟节点数量为 200,服务器 serverNode1 的命中次数为96410虚拟节点数量为 200,服务器 serverNode0 的命中次数为99399虚拟节点数量为 250,服务器 serverNode9 的命中次数为100820虚拟节点数量为 250,服务器 serverNode8 的命中次数为97893虚拟节点数量为 250,服务器 serverNode7 的命中次数为101562虚拟节点数量为 250,服务器 serverNode6 的命中次数为106167虚拟节点数量为 250,服务器 serverNode5 的命中次数为95834虚拟节点数量为 250,服务器 serverNode4 的命中次数为104858虚拟节点数量为 250,服务器 serverNode3 的命中次数为98374虚拟节点数量为 250,服务器 serverNode2 的命中次数为97810虚拟节点数量为 250,服务器 serverNode1 的命中次数为98218虚拟节点数量为 250,服务器 serverNode0 的命中次数为98464虚拟节点数量为 300,服务器 serverNode9 的命中次数为91489虚拟节点数量为 300,服务器 serverNode8 的命中次数为102993虚拟节点数量为 300,服务器 serverNode7 的命中次数为101695虚拟节点数量为 300,服务器 serverNode6 的命中次数为101534虚拟节点数量为 300,服务器 serverNode5 的命中次数为95657虚拟节点数量为 300,服务器 serverNode4 的命中次数为109415虚拟节点数量为 300,服务器 serverNode3 的命中次数为94634虚拟节点数量为 300,服务器 serverNode2 的命中次数为101595虚拟节点数量为 300,服务器 serverNode1 的命中次数为102359虚拟节点数量为 300,服务器 serverNode0 的命中次数为98629虚拟节点数量为 400,服务器 serverNode9 的命中次数为93989虚拟节点数量为 400,服务器 serverNode8 的命中次数为98911虚拟节点数量为 400,服务器 serverNode7 的命中次数为117310虚拟节点数量为 400,服务器 serverNode6 的命中次数为102818虚拟节点数量为 400,服务器 serverNode5 的命中次数为98519虚拟节点数量为 400,服务器 serverNode4 的命中次数为96831虚拟节点数量为 400,服务器 serverNode3 的命中次数为95536虚拟节点数量为 400,服务器 serverNode2 的命中次数为98536虚拟节点数量为 400,服务器 serverNode1 的命中次数为97318虚拟节点数量为 400,服务器 serverNode0 的命中次数为100232虚拟节点数量为 500,服务器 serverNode9 的命中次数为91246虚拟节点数量为 500,服务器 serverNode8 的命中次数为101325虚拟节点数量为 500,服务器 serverNode7 的命中次数为110125虚拟节点数量为 500,服务器 serverNode6 的命中次数为104245虚拟节点数量为 500,服务器 serverNode5 的命中次数为101343虚拟节点数量为 500,服务器 serverNode4 的命中次数为101815虚拟节点数量为 500,服务器 serverNode3 的命中次数为94576虚拟节点数量为 500,服务器 serverNode2 的命中次数为100973虚拟节点数量为 500,服务器 serverNode1 的命中次数为96725虚拟节点数量为 500,服务器 serverNode0 的命中次数为97627虚拟节点数量为 1000,服务器 serverNode9 的命中次数为97321虚拟节点数量为 1000,服务器 serverNode8 的命中次数为100783虚拟节点数量为 1000,服务器 serverNode7 的命中次数为104555虚拟节点数量为 1000,服务器 serverNode6 的命中次数为96789虚拟节点数量为 1000,服务器 serverNode5 的命中次数为96124虚拟节点数量为 1000,服务器 serverNode4 的命中次数为99348虚拟节点数量为 1000,服务器 serverNode3 的命中次数为102450虚拟节点数量为 1000,服务器 serverNode2 的命中次数为100374虚拟节点数量为 1000,服务器 serverNode1 的命中次数为99537虚拟节点数量为 1000,服务器 serverNode0 的命中次数为102719虚拟节点数量为 1,标准差为:74008虚拟节点数量为 5,标准差为:41044虚拟节点数量为 100,标准差为:6784虚拟节点数量为 120,标准差为:7834虚拟节点数量为 140,标准差为:7797虚拟节点数量为 150,标准差为:6549虚拟节点数量为 180,标准差为:5122虚拟节点数量为 200,标准差为:5094虚拟节点数量为 250,标准差为:3325虚拟节点数量为 300,标准差为:5087虚拟节点数量为 400,标准差为:6553虚拟节点数量为 500,标准差为:5278虚拟节点数量为 1000,标准差为:2750
划线
评论
复制
发布于: 2020 年 07 月 09 日 阅读数: 29
坂田吴奇隆
关注
还未添加个人签名 2019.01.06 加入
还未添加个人简介
评论