写点什么

架构师训练营 -week5

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

作业

  • 用你熟悉的编程语言实现一致性 hash 算法。

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



/**
* @Author hxchen
* @Date 2020/7/8
*/
public class NodeCircle {
public static void main(String[] args) {
final int serverCount = 10;
final int eachServerNodeCount = 1000;
List<Server> serverList = new ArrayList<>();
for (int i = 0; i < serverCount; i++) {
serverList.add(new Server(i, eachServerNodeCount));
}
List<VirtualNode> circleOrderedVirtualNodes = new ArrayList<>();
serverList.forEach(server -> circleOrderedVirtualNodes.addAll(server.getVirtualNodes()));
long[] arr = circleOrderedVirtualNodes.stream().map(VirtualNode::getCircleIndex)
.sorted(Long::compareTo).mapToLong(Long::longValue).toArray();
circleOrderedVirtualNodes.sort(Comparator.comparing(virtualNode -> virtualNode.circleIndex));
final int keyValueCount = 100_0000; //100_0000
for (int i = 0; i < keyValueCount; i++) {
long key = new Random().nextLong() & 0xffffffffL;
// System.out.println(key);
int keyIndex = getIndex(key, arr);
// System.out.println("key circle index" + keyIndex);
VirtualNode node = circleOrderedVirtualNodes.get(keyIndex);
node.setHitCount(node.hitCount + 1);
}
System.out.println("标准差为:" + new StandardDeviation().getStandardDeviation(serverList, keyValueCount));
}
static int getIndex(long key, long[] a) {
if (key > a[a.length - 1] || key < a[0]) {
return 0;
}
return bsearch(a, key);
}
// modify binary search to return the right index
static int bsearch(long a[], long key) {
int low = 0;
int high = a.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (a[mid] > key)
high = mid - 1;
else if (a[mid] < key)
low = mid + 1;
else
return mid;
}
//this is diffrent from usual return -1;
return low;
}
}
class Server {
int serverIndex;
int allHit;
List<VirtualNode> virtualNodes = new ArrayList<>();
public Server(int serverIndex, int virtualNodesCount) {
this.serverIndex = serverIndex;
for (int i = 0; i < virtualNodesCount; i++) {
virtualNodes.add(new VirtualNode(i, new Random().nextLong() & 0xffffffffL));
}
virtualNodes.sort(Comparator.comparing(VirtualNode::getCircleIndex));
}
public void printHit() {
System.out.println("++++++++++++++++++++++++");
System.out.println("++++++++++++++"+ "server" + serverIndex + " hit:" + getAllHit() + "次" + "++++++++++++++");
// virtualNodes.forEach(v -> {
// System.out.println("Node-(circleIndex)" + v.getCircleIndex() + " hit: " + v.getHitCount() + "次");
// });
System.out.println("");
}
public List<VirtualNode> getVirtualNodes() {
return virtualNodes;
}
public int getServerIndex() {
return serverIndex;
}
public int getAllHit() {
return virtualNodes.stream().mapToInt(VirtualNode::getHitCount).sum();
}
public void setAllHit(int allHit) {
this.allHit = allHit;
}
}
class StandardDeviation {
public Double getStandardDeviation(List<Server> servers, int allHit) {
int serverSize = servers.size();
int averageHit = allHit / serverSize;
int temp = 0;
System.out.println("平均hit:" + averageHit);
for (Server s : servers) {
s.printHit();
temp += Math.pow(s.getAllHit() - averageHit, 2);
}
Double standardDeviation = Math.sqrt(temp / serverSize);
return standardDeviation;
}
}
class VirtualNode {
int belongServerIndex;
long circleIndex;
int hitCount = 0;
public VirtualNode(int belongServerIndex, long circleIndex) {
this.belongServerIndex = belongServerIndex;
this.circleIndex = circleIndex;
}
public int getBelongServerIndex() {
return belongServerIndex;
}
public long getCircleIndex() {
return circleIndex;
}
public void setHitCount(int hitCount) {
this.hitCount = hitCount;
}
public int getHitCount() {
return hitCount;
}
public void setIndex(long index) {
if (index == (2 ^ 32)) {
throw new ArrayIndexOutOfBoundsException("数组下标最大为2^32 -1");
}
this.circleIndex = index;
}
}

总结

从2个方面简单总结下

  1. 上面这个作业说几点

首先困难的是理解题意

这个题目的重点是是什么?我是不是要写一个hash算法算出100w个keyValue的位置?那我如何设定这100w个key或者value呢?用guid?hash算法怎么定?越想越觉得不清晰。而且服务节点如何设置其信息,要用mac地址吗?以及虚拟节点,也是同样的问题。这几个问题有个共性,就是随机,我不知道他们是什么,那我就都随机好了。现实中的key,value也是随机出现的。因此用2^32内的随机数来抽象keyvalue及服务器虚拟节点的位置,就省得算hash了,似乎不错哦。

其次选择什么数据结构

印象里掌握的数据结构不多,对java中现有数据结构的底层也不是特别清晰,这个环很有迷惑性。总想搞个链表,但是查找插入的Key的位置不是链表擅长的。肯定不行,这里面逃不掉的是比较,然后平衡有序二叉树又浮现出来,可惜还是不知怎么下手,再思考,关键是先要有序,有序之后再比较位置就方便多了,此时想到二分查找,非常好,但是二分查找算法是查找存在或不存在,稍加分析,将二分查找最后return -1的值改了改,二分查找便可以返回该放入的节点的索引。

理解标准差的含义

结合标准差的含义,这边最后统计的是服务器的命中标准差,不是虚拟节点的。

代码不断重构,得到比较好的模型

最初我就通过数组来操作,连虚拟节点都没有,但是逐渐发现数组存的信息太少,因此不断增加虚拟节点类,服务器类,方差计算类,这样的代码就更加灵活了,有点面向对象的意思哈。

到了总结的时候了

其实我不太清楚上面程序是否符合题目的本意,这是对一致性哈希算法的正确模拟吗?有待求证。其次30分钟我写不出来。最重要的是这真的是锻炼思维的好题目啊!!赞!



  1. 本节课内容

本节课主要学习了缓存。缓存无处不在,存在请求链路的各环节,本质是为了解决低效读取问题,缓存技术

比较纯粹,强大,我们应该正确运用缓存,提高应用性能,同时降低缓存误用,防止导致服务器雪崩等一连串事故。



用户头像

强哥

关注

这个强哥不太弱 2019.08.06 加入

肚子里的货都在文字里了。

评论

发布
暂无评论
架构师训练营-week5