写点什么

第五周 作业 1

用户头像
Yangjing
关注
发布于: 2020 年 10 月 25 日
第五周 作业1
  1. 用你熟悉的编程语言实现一致性 hash 算法。

ConsistentHash.java


public class ConsistentHash { private static ConcurrentSkipListMap<Integer, String> nodes = new ConcurrentSkipListMap(); // 每台机器虚拟节点数默认为 150 private int virtualNumPerNode = 150;
public ConsistentHash(List<String> nodes, int virtualNumPerNode) { this.virtualNumPerNode = virtualNumPerNode; for (String node:nodes) { addVirtualNodes(node); } }
private void addVirtualNodes(String node) { for (int i=0; i<this.virtualNumPerNode; i++) { // 虚拟节点使用 192.168.1.1#1 表示虚拟的第几个节点 String virtualNode = node+"#"+i; nodes.put(getHash(virtualNode), virtualNode); } } // 根据 key 找到存储数据的真实机器节点 public String getNode(Object key) { Integer hashCode = getHash(key); Map.Entry<Integer, String> entry = nodes.ceilingEntry(hashCode); if (entry == null) { entry = nodes.ceilingEntry(0); } String virtualNode = entry.getValue(); return virtualNode.substring(0, virtualNode.indexOf("#")); } // 使用FNV1_32_HASH算法计算服务器的Hash值,hash值能大于 2^31 private int getHash(Object object) { final int p = 16777619; int hash = (int) 2166136261L; String string = object.toString();
for (int i = 0; i < string.length(); i++) hash = (hash ^ string.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; //return Math.abs(string.hashCode()); }}
复制代码


  1. 编写测试用例测试这个算法,测试 100w kv 数据,10 个服务器节点的情况下,计算这些 KV 数据在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。

MathUtils.java

public class MathUtils {	// 求平均数	public static Double averageValue(Integer[] data) {		Double sum = 0.0;		for (Integer d:data) {			sum += d;		}		return sum/data.length;	}
// 求标准差 public static Double standardVariance(Integer[] data) { Double avg = MathUtils.averageValue(data); Double var = 0.0; for (Integer d:data) { // 当前数与平均数的差的平方 var += ((d-avg)*(d-avg)); }
return Math.sqrt((var/data.length)); }}
复制代码


ConsistentHashTest.java

public class ConsistentHashTest {
@Test public void getNode() { List<String> nodes = Arrays.asList( "192.168.0.1", "192.168.0.2", "192.168.0.3", "192.168.0.4", "192.168.0.5", "192.168.0.6", "192.168.0.7", "192.168.0.8", "192.168.0.9", "192.168.0.10" ); ConsistentHash consistentHash = new ConsistentHash(nodes, 250);
Map<String, Integer> stat = new HashMap<>();
for (int i=0; i<1000000; i++) { String randomString = generateRandomString(); String node = consistentHash.getNode(randomString); stat.put(node, stat.getOrDefault(node, 0)+1); } for (String node:nodes) { System.out.println("node: "+node+"; count: "+ stat.get(node)); }
Integer[] data = stat.values().toArray(new Integer[0]); Double standardVariance = MathUtils.standardVariance(data); System.out.println("sdv => "+standardVariance); }
private String generateRandomString() { return UUID.randomUUID().toString(); }}
复制代码

将虚拟节点设置为不同值得到的标准差见下表


得出逻辑不完全精确的结论是:当节点数很少时每个节点的存放的 key 数稳定,随着节点增多,每个机器的存放数量波动越小,当节点大于 150 后,随着节点数增多,波动减小的效果逐渐变差。


发布于: 2020 年 10 月 25 日阅读数: 47
用户头像

Yangjing

关注

还未添加个人签名 2017.11.09 加入

还未添加个人简介

评论

发布
暂无评论
第五周 作业1