第五周作业
模拟10个节点,并打印出标准差
package com.hash;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class ConsistentHashingWithVirtualNode<T> {
private final HashFunction hashFunction;// hash 函数接口
private final int numberOfReplicas;// 每个机器节点关联的虚拟节点个数
private final SortedMap<Long, T> circle = new TreeMap<Long, T>();// 环形虚拟节点
private static final String IP_PREFIX = "192.168.1.";// 机器节点IP前缀
public ConsistentHashingWithVirtualNode(HashFunction hashFunction, int numberOfReplicas, Collection<T> nodes) {
this.hashFunction = hashFunction;
this.numberOfReplicas = numberOfReplicas;
for (T node : nodes) {
add(node);
}
}
/**
* 增加真实机器节点
*
* @param node
*/
public void add(T node) {
for (int i = 0; i < this.numberOfReplicas; i++) {
circle.put(this.hashFunction.hash(node.toString() + i), node);
}
}
/**
* 删除真实机器节点
*
* @param node
*/
public void remove(T node) {
for (int i = 0; i < this.numberOfReplicas; i++) {
circle.remove(this.hashFunction.hash(node.toString() + i));
}
}
/**
* 取得真实机器节点
*
* @param key
* @return
*/
public T get(String key) {
if (circle.isEmpty()) {
return null;
}
long hash = hashFunction.hash(key);
if (!circle.containsKey(hash)) {
SortedMap<Long, T> tailMap = circle.tailMap(hash);// 沿环的顺时针找到一个虚拟节点
hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();
}
return circle.get(hash); // 返回该虚拟节点对应的真实机器节点的信息
}
public static void main(String[] args) {
// 开启多线程测试10w个kv的效果
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
Map<String, Integer> map = new HashMap<String, Integer>();// 每台真实机器节点上保存的记录条数
List<Node<String>> nodes = new ArrayList<Node<String>>();// 真实机器节点
// 10台真实机器节点集群
for (int i = 1; i <= 10; i++) {
map.put(IP_PREFIX + i, 0);// 每台真实机器节点上保存的记录条数初始为0
Node<String> node = new Node<String>(IP_PREFIX + i, "node" + i);
nodes.add(node);
}
HashFunction hashFunction = new HashFunctionImpl(); // hash函数实例
ConsistentHashingWithVirtualNode<Node<String>> consistentHash = new ConsistentHashingWithVirtualNode<Node<String>>(hashFunction, 100, nodes);// 每台真实机器引入100个虚拟节点
// 10w条kv数据
for (int i = 0; i < 100000; i++) {
// 产生随机一个字符串当做一条记录,可以是其它更复杂的业务对象,比如随机字符串相当于对象的业务唯一标识
String data = UUID.randomUUID().toString() + i;
// 通过记录找到真实机器节点
Node<String> node = consistentHash.get(data);
map.put(node.getIp(), map.get(node.getIp()) + 1);
}
int powSum = 0; // 平方和
for (int i = 1; i <= 10; i++) {
int c = map.get("192.168.1." + i);
powSum += Math.pow((c - 10000), 2);
}
System.out.println("标准差为:" + Math.sqrt(powSum / 10));
}
}
/**
* 虚拟节点
*
* @param <T>
*/
class Node<T> {
private String ip;// IP
private String name;// 名称
public Node(String ip, String name) {
this.ip = ip;
this.name = name;
}
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;
}
/**
* 复写toString方法,使用节点IP当做hash的KEY
*/
@Override
public String toString() {
return ip;
}
}
评论