架构师训练营 -week5 命题作业
发布于: 2020 年 07 月 04 日
作业:
用你熟悉的编程语言实现一致性 hash 算法。
编写测试用例测试这个算法,测试 100 万 KV 数据,10 个服务器节点的情况下,计算这些 KV 数据在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。
package jiketime_homework.week05;import java.util.LinkedList;import java.util.List;import java.util.SortedMap;import java.util.TreeMap;/** * @Author jeffSmile * @Date 下午 5:22 2020/7/4 0004 * @Description //TODO * 用你熟悉的编程语言实现一致性 hash 算法。 **/public class ConsistentHashingWithVirtualNode { /** * 待添加入Hash环的服务器列表 */ private static String[] servers = {"192.168.0.0:11211", "192.168.0.1:11211", "192.168.0.2:11211","192.168.0.3:11211", "192.168.0.4:11211", "192.168.0.5:11211", "192.168.0.6:11211", "192.168.0.7:11211","192.168.0.8:11211", "192.168.0.9:11211"}; /** * 真实结点列表,考虑到服务器上线、下线的场景,即添加、删除的场景会比较频繁,这里使用LinkedList会更好 */ private static List<String> realNodes = new LinkedList<String>(); /** * 虚拟节点,key表示虚拟节点的hash值,value表示虚拟节点的名称 */ private static SortedMap<Integer, String> virtualNodes = new TreeMap<Integer, String>(); /** * 虚拟节点的数目,一个真实结点对应5个虚拟节点 */ private static int VIRTUAL_NODES = 5; public ConsistentHashingWithVirtualNode(){ this(VIRTUAL_NODES, servers); } public ConsistentHashingWithVirtualNode(int virNodes, String[] servers){ this.servers=servers; this.VIRTUAL_NODES = virNodes; initHashCircle(); } public void initHashCircle() { System.out.println("构造hash环==========开始============="); // 先把原始的服务器添加到真实结点列表中 for (int i = 0; i < servers.length; i++) realNodes.add(servers[i]); // 再添加虚拟节点,遍历LinkedList使用foreach循环效率会比较高 for (String str : realNodes) { for (int i = 0; i < VIRTUAL_NODES; i++) { String virtualNodeName = str + "&&MEMCACHED_" + String.valueOf(i); int hash = getHash(virtualNodeName);// System.out.println("虚拟节点[" + virtualNodeName + "]被添加, hash值为" + hash); virtualNodes.put(hash, virtualNodeName); } } System.out.println("构造hash环==========完毕============="); } /** * 使用FNV1_32_HASH算法计算服务器的Hash值 */ public 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; } /** * 得到应当路由到的结点 */ public String getServer(String node) { // 得到带路由的结点的Hash值 int hash = getHash(node); // 得到大于该Hash值的所有Map SortedMap<Integer, String> subMap = virtualNodes.tailMap(hash); Integer i = 0; String virtualNode = null; if(!subMap.isEmpty()){ // 第一个Key就是顺时针过去离node最近的那个结点 i = subMap.firstKey(); // 返回对应的虚拟节点名称 virtualNode = subMap.get(i); }else{ i = virtualNodes.firstKey(); virtualNode = virtualNodes.get(i); } return virtualNode.substring(0, virtualNode.indexOf("&&")); } public static void main(String[] args) { ConsistentHashingWithVirtualNode consistentHash = new ConsistentHashingWithVirtualNode();// String[] nodes = {"127.0.0.1", "47.107.125.20", "172.18.75.44"};// for (int i = 0; i < nodes.length; i++)// System.out.println("[" + nodes[i] + "]的hash值为" + consistentHash.getHash(nodes[i]) + ", 被路由到结点[" + consistentHash.getServer(nodes[i]) + "]"); System.out.println(consistentHash.getServer("77")); }}
package jiketime_homework.week05;import java.util.List;public class StandardDeviaction { //计算和 public static double calcSum(List<Integer> list){ double sum = 0; for(int i = 0;i<list.size();i++){ sum += list.get(i); } return sum; } //求平均值 public static double mean(List<Integer> list){ return calcSum(list) / list.size(); } //求标准差 public static double standardDeviaction(List<Integer> list){ double sum = 0; double meanValue = mean(list); //平均数 for(int i = 0;i < list.size();i++){ sum += Math.pow(list.get(i)-meanValue, 2); } return Math.sqrt(sum/list.size()); }}
package jiketime_homework.week05;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * @author jeffSmile * @date 2020-07-04 下午 5:37 * @desc 编写测试用例测试这个算法,测试 100 万 KV 数据,10 个服务器节点的情况下,计算这些 KV 数据在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。 */public class TestConsistentHash { /** * @Author jeffSmile * @Date 下午 5:38 2020/7/4 0004 * @Description 将100万数据计算hash,并计算hash环上服务器10个节点各自被命中的总数 **/ public static Map<String,Integer> loadCache(ConsistentHashingWithVirtualNode consistentHash){ Map<String,Integer> blanceMap = new HashMap<>(); for (int i = 0; i < 1000000; i++) { String server = consistentHash.getServer(String.valueOf(i)); if(blanceMap.get(server)==null){ blanceMap.put(server,1); }else{ blanceMap.put(server, blanceMap.get(server)+1); } } return blanceMap; } public static void main(String[] args) { ConsistentHashingWithVirtualNode consistentHash = new ConsistentHashingWithVirtualNode(); Map<String,Integer> blanceMap = loadCache(consistentHash); List<Integer> blanceList = new ArrayList<>(); for (String key : blanceMap.keySet()) { System.out.println(key+"节点上存储数据量:"+blanceMap.get(key)); blanceList.add(blanceMap.get(key)); } double standardDeviaction = StandardDeviaction.standardDeviaction(blanceList); System.out.println("标准差为:"+standardDeviaction); }}
划线
评论
复制
发布于: 2020 年 07 月 04 日 阅读数: 41
版权声明: 本文为 InfoQ 作者【Jeff.Spring】的原创文章。
原文链接:【http://xie.infoq.cn/article/950aa1caf3f975fab8d1c4174】。文章转载请联系作者。
Jeff.Spring
关注
努力支撑经历,经历支撑能力! 2018.12.03 加入
追不上BAT的人... 分享,聚焦
评论