架构师训练营第五周课后作业

用户头像
Gosling
关注
发布于: 2020 年 10 月 25 日

本周的作业主要考察对一致性哈希算法的理解,这里采用Java语言来实现对一致性哈希算法的实现并验证对于不同虚拟节点下的情况下,评估不同服务器的负载差异情况。

编程实现一致性哈希算法

AbstractServerInstance类

/**
* 名称: AbstractServerInstance.java
* 描述:
* @author Gosling
* date: 2020年10月22日 下午2:18:39
*/
package com.gosling;
/**
* @ClassName: AbstractServerInstance
* @Description: 服务器抽象类
* @author: Gosling
* @date: 2020年10月22日 下午2:18:39
*/
public abstract class AbstractServerInstance {
private String ip;
private String name;
private String description;
public AbstractServerInstance() {
}
public AbstractServerInstance(String ip, String name) {
super();
this.ip = ip;
this.name = name;
}
public AbstractServerInstance(String ip, String name, String description) {
super();
this.ip = ip;
this.name = name;
this.description = description;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

MyServiceInstance类

/**
* 名称: MyServiceInstance.java
* 描述:
* @author Gosling
* date: 2020年10月22日 下午2:20:57
*/
package com.gosling;
/**
* @ClassName: MyServiceInstance
* @Description: TODO
* @author: Gosling
* @date: 2020年10月22日 下午2:20:57
*/
public class MyServiceInstance extends AbstractServerInstance{
public MyServiceInstance() {
}
public MyServiceInstance(String ip, String name) {
super(ip, name);
}
}

ConsistentHashing类

/**
* 名称: ConsistentHashing.java
* 描述:
* @author Gosling
* date: 2020年10月22日 下午1:41:57
*/
package com.gosling;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* @ClassName: ConsistentHashing
* @Description: 一致性Hash
* @author: shengling.guan
* @date: 2020年10月22日 下午1:41:57
*/
public class ConsistentHashing {
public static final int DEFAULT_VIRTUAL_NODES_NUM = 50;
private static List<AbstractServerInstance> serverList = new ArrayList<>();
private int serverNum = 0;
private SortedMap<Long,AbstractServerInstance> virtualNodesMap = new TreeMap<>();
private int virtualNodes;
public ConsistentHashing() {
this.virtualNodes = 50;
}
public ConsistentHashing(int virtualNodes) {
this.virtualNodes = DEFAULT_VIRTUAL_NODES_NUM;
}
public Long hash(String key) {
ByteBuffer buf = ByteBuffer.wrap(key.getBytes());
int seed = 0x1234ABCD;
ByteOrder byteOrder = buf.order();
buf.order(ByteOrder.LITTLE_ENDIAN);
long m = 0xc6a4a7935bd1e995L;
int r = 47;
long h = seed ^ (buf.remaining() * m);
long k;
while (buf.remaining() >= 8) {
k = buf.getLong();
k *= m;
k ^= k >>> r;
k *= m;
h ^= k;
h *= m;
}
if (buf.remaining() > 0) {
ByteBuffer finish = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);
finish.put(buf).rewind();
h ^= finish.getLong();
h *= m;
}
h ^= h >>> r;
h *= m;
h ^= h >>> r;
buf.order(byteOrder);
return h;
}
public void handleVirtualMapping() {
//导入虚拟节点,建立虚拟节点和真实节点的映射
for(int i = 0,size = virtualNodes; i < size; i++) {
AbstractServerInstance targetServer = serverList.get(i % serverNum);
long virtualNode = hash(targetServer.getIp() + "#" + i);
virtualNodesMap.put(virtualNode, targetServer);
}
}
public void initServerInstance(List<AbstractServerInstance> list) {
serverList.addAll(list);
serverNum = serverList.size();
}
public AbstractServerInstance routing(String key) {
long hashCode = hash(key);
if(!virtualNodesMap.containsKey(hashCode));{
SortedMap<Long, AbstractServerInstance> tailMap = virtualNodesMap.tailMap(hashCode);
if(tailMap.isEmpty()) {
hashCode = virtualNodesMap.firstKey();
}else {
hashCode = tailMap.firstKey();
}
}
return virtualNodesMap.get(hashCode);
}
public int getVirtualNodes() {
return virtualNodes;
}
}

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

public void testHash() {
ConsistentHashing sample = new ConsistentHashing(20);
List<AbstractServerInstance> list = new ArrayList<>();
int serverNum = 10;
Map<String,Integer> statMap = new HashMap<>();
for (int i = 1; i <= serverNum; i++) {
AbstractServerInstance server = new MyServiceInstance("192.168.3."+i,"s"+i);
list.add(server);
statMap.put("192.168.3."+i, 0);
}
sample.initServerInstance(list);
sample.handleVirtualMapping();
for (int i = 0; i < 1000000; i++) {
//String key = UUID.randomUUID().toString() + i;
String key = i+"";
AbstractServerInstance server = sample.routing(key);
statMap.put(server.getIp(), statMap.get(server.getIp()) + 1);
}
int sum = 0;
double avg = 0D;
for (int i = 1; i <= serverNum; i++) {
System.out.println("192.168.3." + i + "节点记录条数:" + statMap.get("192.168.3."+i));
sum += statMap.get("192.168.3."+i);
}
avg = sum / serverNum;
double tempSum = 0;
for (int i = 1; i <= serverNum; i++) {
tempSum += Math.sqrt(((double) statMap.get("192.168.3." + i) - avg) * (statMap.get("192.168.3." + i) - avg));
}
System.out.println("标准差:" + (tempSum / (serverNum - 1)));
}



用户头像

Gosling

关注

还未添加个人签名 2017.10.28 加入

还未添加个人简介

评论

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