写点什么

架构师训练营第五周作业

用户头像
张锐
关注
发布于: 2020 年 07 月 08 日



import java.util.Arrays;
import java.util.Random;
/**
* @author ray.zhangr
* @date 2020/7/8 9:57 下午
*/
public class ConsistentHash {
private int serverNum;
private int[] svrLocation;
public ConsistentHash(int serverNum) {
this.serverNum = serverNum;
this.svrLocation = serverLocate(serverNum);
}
private int[] serverLocate(int serverNum) {
int[] svrLocation = new int[serverNum];
for (int i = 0; i < serverNum; i++) {
svrLocation[i] = new Random().nextInt(); // 用当前日期的哈希值模拟服务器的哈希值
}
Arrays.sort(svrLocation);
return svrLocation;
}
public int[] dataBelong(int[] keysHash) {
int[] belongs = new int[serverNum];
for (int keyHash : keysHash) {
for (int i = 0; i < serverNum; i++) {
if (keyHash <= svrLocation[i]) {
belongs[i]++;
break;
}
}
if (keyHash > svrLocation[serverNum - 1])
belongs[0]++;
}
return belongs;
}
public static void main(String args[]) {
ConsistentHash ch = new ConsistentHash(10);
int[] dataset = new int[1000000];
for (int i = 0; i < 1000000; i++) {
dataset[i] = new Random().nextInt();
}
int[] belongs = ch.dataBelong(dataset);
for (int i = 0; i < belongs.length; i++) {
System.out.println(String.format("Server %s: %s", i, belongs[i]));
}
// 评估标准差
System.out.println("标准差" + StandardDiviation(belongs));
}
public static double StandardDiviation(int[] x) {
int m=x.length;
double sum=0;
for(int i=0;i<m;i++){//求和
sum+=x[i];
}
double dAve=sum/m;//求平均值
double dVar=0;
for(int i=0;i<m;i++){//求方差
dVar+=(x[i]-dAve)*(x[i]-dAve);
}
//reture Math.sqrt(dVar/(m-1));
return Math.sqrt(dVar/m);
}
}

运行结果1:

运行结果2:



由于server的hash值分布不均匀,可以看出有的段内只落了几千个key,有的多的落了20w的key,分布在机器数量很少的情况下是不均匀的。所以用虚拟节点来看,就是为了最大化平均哈希环上机器的分布。

在群里看到不少同学已经实现了虚拟节点下的一致性hash算法,并用图表模拟了下虚拟节点数量和标准差的关系。贴出自己实现的虚拟节点的一致性哈希实现:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
/**
* @author ray.zhangr
* @date 2020/7/9 10:07 上午
*/
public class ConsistentHashWithVirtualNode {
private int serverNum;
private int multiple;
private List<VirtualNode> nodes = new ArrayList<>();
public ConsistentHashWithVirtualNode(int serverNum, int multiple) {
this.serverNum = serverNum;
this.multiple = multiple;
for (int i = 0; i < serverNum; i++) {
for (int j = 0; j < multiple; j++) {
VirtualNode node = new VirtualNode(new Random().nextInt(), i);
nodes.add(node);
}
}
Collections.sort(nodes);
}
public int[] dataBelong(int[] keysHash) {
int[] belongs = new int[serverNum];
int virtualNodeNum = nodes.size();
for (int keyHash : keysHash) {
for (int i = 0; i < virtualNodeNum; i++) {
if (keyHash <= nodes.get(i).hashCode) {
belongs[nodes.get(i).belongServer]++;
break;
}
}
if (keyHash > nodes.get(virtualNodeNum - 1).hashCode)
belongs[nodes.get(virtualNodeNum - 1).belongServer]++;
}
return belongs;
}
class VirtualNode implements Comparable<VirtualNode> {
private int hashCode;
private int belongServer;
VirtualNode(int hashCode, int belongServer) {
this.hashCode = hashCode;
this.belongServer = belongServer;
}
@Override
public int compareTo(VirtualNode o) {
return this.hashCode > o.hashCode ? 1 : -1;
}
}
public static void main(String args[]) {
ConsistentHashWithVirtualNode ch = new ConsistentHashWithVirtualNode(10, 20);
int[] dataset = new int[1000000];
for (int i = 0; i < 1000000; i++) {
dataset[i] = new Random().nextInt();
}
int[] belongs = ch.dataBelong(dataset);
for (int i = 0; i < belongs.length; i++) {
System.out.println(String.format("Server %s: %s", i, belongs[i]));
}
// 评估标准差
System.out.println("标准差" + StandardDiviation(belongs));
}
public static double StandardDiviation(int[] x) {
int m=x.length;
double sum=0;
for(int i=0;i<m;i++){//求和
sum+=x[i];
}
double dAve=sum/m;//求平均值
double dVar=0;
for(int i=0;i<m;i++){//求方差
dVar+=(x[i]-dAve)*(x[i]-dAve);
}
//reture Math.sqrt(dVar/(m-1));
return Math.sqrt(dVar/m);
}
}

运行两次的实验结果如下:



可以看到标准差有明显的降低。虽然还是10个节点,但是每个节点分配的key数量比较均等,没再出现只有几千的key分配的情况。

用户头像

张锐

关注

还未添加个人签名 2018.08.07 加入

还未添加个人简介

评论

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