写点什么

架构师训练营第 1 期 week5

用户头像
张建亮
关注
发布于: 2020 年 10 月 24 日



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



import java.util.*;
public class ConsistantHash {
public static String[] ip;//物理节点
public static int virtualIp = 200;//虚拟ip的数量
//用来虚拟节点的标识
public static String flag = "@#!";
//虚拟节点到IP的映射关系
public static TreeMap<Long,String> vituralToIp = new TreeMap<Long,String>();
//记录每个ip存储的key的数量
public static Map<String,Integer> ipValueCount = new HashMap<String,Integer>();
//添加物理节点
public static void addNode(String ip){
ipValueCount.put(ip,0);
//long ipHash = FNVHash(ip);
for(int i=0;i<virtualIp;i++){
Long hash = FNVHash(ip+flag+i);
vituralToIp.put(hash,ip);
}
}
//删除物理节点
public static void removeNode(String ip){
for(int i=0;i<virtualIp;i++){
vituralToIp.remove(FNVHash(ip+flag+i));
}
}
//插入对象映射的ip,暂时先按key是字符串处理
public static String valueToNode(String key){
long hash = FNVHash(key);
//获取比hash值大的数的集合
SortedMap<Long, String> gtHash = vituralToIp.tailMap(hash);
Long resultKey = gtHash.isEmpty()?vituralToIp.firstKey():gtHash.firstKey();
return vituralToIp.get(resultKey);
}
// 32位的 Fowler-Noll-Vo 哈希算法
private static Long FNVHash(String key) {
final int p = 16777619;
Long hash = 2166136261L;
for (int idx = 0, num = key.length(); idx < num; ++idx) {
hash = (hash ^ key.charAt(idx)) * p;
}
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
if (hash < 0) {
hash = Math.abs(hash);
}
return hash;
}
public static void main(String[] args) {
ip = new String[]{"192.168.1.1","192.168.1.2","192.168.1.3","192.168.1.4"};
for(String s:ip){
addNode(s);
}
//for(Map.Entry<Long,String> entry:vituralToIp.entrySet()){
//System.out.println(entry.getValue());
//}
int num = 1000000;
bzcValueToIp(num);
}
//测试指定数据在不同IP的分配情况,以标准差的形式体现
public static void bzcValueToIp(int num){
String key ="";
String ip ="";
for(int i=0;i<num;i++){
key = UUID.randomUUID().toString()+flag+num;
ip = valueToNode(key);
ipValueCount.put(ip,ipValueCount.get(ip)+1);
}
System.out.println("随机key的数量:"+num);
System.out.println("虚拟节点的的数量为:"+virtualIp);
// double bzc = 0;
List<Integer> resultList = new ArrayList<Integer>();
for (Map.Entry<String,Integer> entry:ipValueCount.entrySet()){
System.out.println("ip为"+entry.getKey()+"的主机存储数量为:"+entry.getValue());
resultList.add(entry.getValue());
}
int iplength = ip.length();
double avg = num/iplength;//平均值
double bzc = Math.sqrt(resultList.stream().mapToDouble(a->Math.pow((a-avg),2)).sum()/iplength);
System.out.println("标准差为:"+bzc);
}
}



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

测试结果如下,好像结果不是特别明显。。。

随机key的数量:1000000

虚拟节点的的数量为:1

ip为192.168.1.1的主机存储数量为:124700

ip为192.168.1.3的主机存储数量为:367491

ip为192.168.1.2的主机存储数量为:260096

ip为192.168.1.4的主机存储数量为:247713

标准差为:109066.77262117917



随机key的数量:1000000

虚拟节点的的数量为:20

ip为192.168.1.1的主机存储数量为:111529

ip为192.168.1.3的主机存储数量为:258570

ip为192.168.1.2的主机存储数量为:336592

ip为192.168.1.4的主机存储数量为:293309

标准差为:108653.44901441128



随机key的数量:1000000

虚拟节点的的数量为:50

ip为192.168.1.1的主机存储数量为:240554

ip为192.168.1.3的主机存储数量为:386950

ip为192.168.1.2的主机存储数量为:277699

ip为192.168.1.4的主机存储数量为:94797

标准差为:114788.15283738206



随机key的数量:1000000

虚拟节点的的数量为:100

ip为192.168.1.1的主机存储数量为:292938

ip为192.168.1.3的主机存储数量为:314103

ip为192.168.1.2的主机存储数量为:140887

ip为192.168.1.4的主机存储数量为:252072

标准差为:104055.3137562378



随机key的数量:1000000

虚拟节点的的数量为:150

ip为192.168.1.1的主机存储数量为:241698

ip为192.168.1.3的主机存储数量为:175591

ip为192.168.1.2的主机存储数量为:234002

ip为192.168.1.4的主机存储数量为:348709

标准差为:103064.3269093275



随机key的数量:1000000

虚拟节点的的数量为:200

ip为192.168.1.1的主机存储数量为:207474

ip为192.168.1.3的主机存储数量为:227151

ip为192.168.1.2的主机存储数量为:187549

ip为192.168.1.4的主机存储数量为:377826

标准差为:106091.69973445356



用户头像

张建亮

关注

还未添加个人签名 2020.07.29 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营第 1 期 week5