写点什么

架构师训练营 - 第五周作业

用户头像
一个节点
关注
发布于: 2020 年 10 月 25 日
  1. 用你熟悉的编程语言实现一致性 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;
}
}



  1. 编写测试用例测试这个算法,测试 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.925449913013
100个虚拟节点,平方差为:18109.49825920089
150个虚拟节点,平方差为:20364.833738579848
200个虚拟节点,平方差为:24623.291112278228
250个虚拟节点,平方差为:27584.167400884155



用户头像

一个节点

关注

还未添加个人签名 2020.07.27 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营 - 第五周作业