架构师训练营:第五周作业 - 一致性 hash 实现
作业:手动实现一致性 hash 算法
分布式一致性 hash 算法原理
有一个有序的环型hash表,hash表上记录着 服务器节点的hash值与节点的映射。
为了使服务器的节点均匀的分布在 hash环上, 在hash环上增加了一些服务器的虚拟节点,虚拟节点被访问时指向真实的节点。
当有数据存入时,存在数据的hash值对应最近的下一个节点上。如果是末尾且没有服务器节点则存在第一个服务器节点上。
当有数据访问时,按照存入的逻辑查询服务器节点访问。
当一个服务器从 hash 环删除时,仅该节点记录的数据丢失。后来的数据按照存入逻辑,存入最近节点的服务器上。
当一个新服务器节点插入到 hash 环上时。新节点与上一个服务器节点间的数据会丢失。
计算在服务器上分布数量的标准差,以评估算法的存储负载不均衡性。
编写测试用例测试这个算法,测试 100万KV 数据,10个服务器节点的情况下,计算这些KV数
实现过程
刚开始拿到这个题目时,感觉应该比较难,虽然分布式的一致性哈希算法到处有有讲解,但是却从来没有想过自己手动去编码实现。许多事情听起来觉得听懂了就会了,但是真正动手做的时候却发现不是那么简单,脑子里面连怎么做的步骤都没有个大概。
这次也是训练营作业要求去做,做的时候才发现自己眼高手低。学东西一点也没有把知识落地过。也庆幸这次作业让我认识到自己的缺点。让我明白以后该怎么去学东西。
一开始自己是没有想法的。不知道怎么去实现。虽然知道大概原理。所以还是看看大佬博客,看到一篇代码很简单的。看完后总结了几个实现分布式一致性算法的要点:
算法设计要点:
需要一个排序的hash表
找到一个hash算法,计算数据的hash值
hash表访问一个key最近的下一个节点,末尾hash访问hash表的第一个节点,这样就构成hash环。
使用java语言
排序hash表使用TreeMap ,hash算法在网上搜了一下,找到一个java实现的hash算法大全类。直接拿过来用。
再往后就是编写代码了,直接上代码:
//一致性hash类。public class ConsistentHash { //构造hash环 public static ConsistentHashMap build(List serverNode, int virtualNodeCount,HashAlgorithm hashAlgorithm) { ConsistentHashMap consistentHash =new ConsistentHashMap(serverNode,virtualNodeCount,hashAlgorithm); consistentHash.initNode(); return consistentHash; } static class ConsistentHashMap{ /** * 有序hash表 */ private TreeMap<Long,String> nodeMap; /** * 虚拟节点数 */ private int virtualNodeCount; /** * 真实的服务器 */ private List<String> serverNode; /** * 使用的hash算法 */ private HashAlgorithm hashAlgorithm; private ConsistentHashMap(List serverNode, int virtualNodeCount, HashAlgorithm hashAlgorithm) { this.nodeMap = new TreeMap<>(); this.serverNode=serverNode; this.virtualNodeCount=virtualNodeCount; this.hashAlgorithm=hashAlgorithm; } private void initNode() { for (String realServer : serverNode) { for(int i=0;i<virtualNodeCount; i++){ String virtualName = new StringBuilder(realServer).append("#vtal").append(i).toString(); nodeMap.put(hash(virtualName), virtualName);// System.out.println("虚拟节点 : "+virtualName + "在hash环的 "+ hash(virtualName) +" 上" ); } } } public String getServerNode(String key) { long hash = hash(key); //获取hash值对应的节点 if( nodeMap.get(hash) != null){ return getRealName(nodeMap.get(hash)); } //获取hash值最近的节点 if ( nodeMap.higherKey(hash) != null) { return getRealName(nodeMap.get(nodeMap.higherKey(hash))); } //获取首节点 if( nodeMap.firstEntry() != null){ return getRealName(nodeMap.firstEntry().getValue()); } return null; } private String getRealName(String virtualNodeName) { return virtualNodeName !=null ? virtualNodeName.substring(0,virtualNodeName.lastIndexOf("#")) : null; } public void addServerNode(String node) { if (serverNode.contains(node)) { return ; } serverNode.add(node); for(int i=0;i<virtualNodeCount; i++){ String virtualName = new StringBuilder(node).append("#vtal").append(i).toString(); nodeMap.put(hash(virtualName), virtualName);// System.out.println("虚拟节点 : "+virtualName + "在hash环的 "+ hash(virtualName) +" 上" ); } } public void removeServerNode(String node) { if(!serverNode.contains(node)){ return ; } serverNode.remove(node); for(int i=0;i<virtualNodeCount; i++){ String virtualName = new StringBuilder(node).append("#vtal").append(i).toString(); nodeMap.remove(hash(virtualName)); } } private long hash(String key) { return hashAlgorithm.hash(key); } }}
//算法接口public interface HashAlgorithm { int hash(String key);}//算法类网上找的。//博客地址:https://www.cnblogs.com/lzl2016/p/6648259.htmlpublic class HashAlgorithms {...}
//测试类public class TestMain { public static void main(String[] args) { //测试一百万个key int totalKeyCount=100_0000; //真实服务器节点数 int serverCount=10; //虚拟节点从每个服务器100个开始 int startVirtualNodeCount=100; testFive( totalKeyCount, serverCount, startVirtualNodeCount, HashAlgorithms::FNVHash1,"FNVHash1"); System.out.println("==============分隔=============="); testFive( totalKeyCount, serverCount, startVirtualNodeCount, HashAlgorithms::APHash,"APHash"); System.out.println("==============分隔=============="); testFive( totalKeyCount, serverCount, startVirtualNodeCount, HashAlgorithms::ELFHash,"ELFHash"); System.out.println("==============分隔=============="); testFive( totalKeyCount, serverCount, startVirtualNodeCount, HashAlgorithms::DJBHash,"DJBHash"); System.out.println("==============分隔=============="); testFive( totalKeyCount, serverCount, startVirtualNodeCount, HashAlgorithms::JSHash,"JSHash"); System.out.println("==============分隔=============="); testFive( totalKeyCount, serverCount, startVirtualNodeCount, HashAlgorithms::RSHash,"RSHash"); System.out.println("==============分隔=============="); testFive( totalKeyCount, serverCount, startVirtualNodeCount, HashAlgorithms::SDBMHash,"SDBMHash"); System.out.println("==============分隔=============="); testFive( totalKeyCount, serverCount, startVirtualNodeCount, HashAlgorithms::bernstein,"bernstein"); System.out.println("==============分隔=============="); testFive( totalKeyCount, serverCount, startVirtualNodeCount, HashAlgorithms::oneByOneHash,"oneByOneHash"); System.out.println("==============分隔=============="); testFive( totalKeyCount, serverCount, startVirtualNodeCount, HashAlgorithms::java,"java"); testOneByOneHash(); } //进一步测试了FNH1 和 oneByone算法 public static void testOneByOneHash() { int totalKeyCount=100_0000; int serverCount=10; int startVirtualNodeCount=200; int count=40; while(count-->0) { test(totalKeyCount, serverCount, startVirtualNodeCount += 20, HashAlgorithms::oneByOneHash, "oneByOneHash"); } System.out.println("==============分隔=============="); int count1=40; startVirtualNodeCount=200; while(count1-->0) { test(totalKeyCount, serverCount, startVirtualNodeCount += 20, HashAlgorithms::FNVHash1, "FNVHash1"); } } //每次加20个虚拟节点,到200个为止 public static void testFive(int totalKeyCount, int serverCount, int virtualNodeCount,HashAlgorithm hashAlgorithm,String algorrithmName){ do{ test( totalKeyCount, serverCount, virtualNodeCount, hashAlgorithm,algorrithmName); }while((virtualNodeCount+=20)<=200); } public static void test(int totalKeyCount, int serverCount, int virtualNodeCount,HashAlgorithm hashAlgorithm,String algorrithmName) { List<String> ipList = new ArrayList<>(); Map<String, Integer> serverHodeCountMap = new HashMap<>(serverCount); for (int i = 0; i < serverCount; i++) { ipList.add("192.168.10." + i); serverHodeCountMap.put("192.168.10." + i, 0); } ConsistentHash.ConsistentHashMap constMap = ConsistentHash.build(ipList, virtualNodeCount,hashAlgorithm); String temp = null; for (int j = 0; j < totalKeyCount; j++) { temp = "testkey" + j; String serverNode = constMap.getServerNode(temp);// System.out.println("key : " + temp + " 被放到服务器 " + serverNode + " 中"); serverHodeCountMap.put(serverNode, serverHodeCountMap.get(serverNode) + 1); } double sd = calculate(serverHodeCountMap, totalKeyCount); System.out.println(serverCount + " 个服务器,每个服务器 " + virtualNodeCount + " 个虚拟节点,测试" + totalKeyCount + " 个key " + ",使用 "+algorrithmName+" 算法,标准差为:" + sd); } //计算标准差 public static double calculate(Map<String, Integer> serverHoldCountMap ,Integer totalCount) { float average = totalCount/1.00f / serverHoldCountMap.size(); float sumAbs=0f; for (String key : serverHoldCountMap.keySet()) { float abs = Math.abs(average - serverHoldCountMap.get(key)); sumAbs=sumAbs+(abs*abs); } double sd = Math.sqrt(sumAbs/serverHoldCountMap.size()); return sd; }}
测试结果
10 个服务器,每个服务器 100 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:7827.24523699110910 个服务器,每个服务器 120 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:7099.08557491737810 个服务器,每个服务器 140 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:8407.64556817186510 个服务器,每个服务器 160 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:10131.30001529912310 个服务器,每个服务器 180 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:8603.72570460030310 个服务器,每个服务器 200 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:8979.737635365524==============分隔==============10 个服务器,每个服务器 100 个虚拟节点,测试1000000 个key ,使用 APHash 算法,标准差为:67049.6222211579610 个服务器,每个服务器 120 个虚拟节点,测试1000000 个key ,使用 APHash 算法,标准差为:64940.37536078768610 个服务器,每个服务器 140 个虚拟节点,测试1000000 个key ,使用 APHash 算法,标准差为:64940.37536078768610 个服务器,每个服务器 160 个虚拟节点,测试1000000 个key ,使用 APHash 算法,标准差为:64940.37536078768610 个服务器,每个服务器 180 个虚拟节点,测试1000000 个key ,使用 APHash 算法,标准差为:64940.37536078768610 个服务器,每个服务器 200 个虚拟节点,测试1000000 个key ,使用 APHash 算法,标准差为:64940.375360787686==============分隔==============10 个服务器,每个服务器 100 个虚拟节点,测试1000000 个key ,使用 ELFHash 算法,标准差为:267992.539597653710 个服务器,每个服务器 120 个虚拟节点,测试1000000 个key ,使用 ELFHash 算法,标准差为:267989.1770948968510 个服务器,每个服务器 140 个虚拟节点,测试1000000 个key ,使用 ELFHash 算法,标准差为:267989.1770948968510 个服务器,每个服务器 160 个虚拟节点,测试1000000 个key ,使用 ELFHash 算法,标准差为:267989.1770948968510 个服务器,每个服务器 180 个虚拟节点,测试1000000 个key ,使用 ELFHash 算法,标准差为:267989.1770948968510 个服务器,每个服务器 200 个虚拟节点,测试1000000 个key ,使用 ELFHash 算法,标准差为:267989.17709489685==============分隔==============10 个服务器,每个服务器 100 个虚拟节点,测试1000000 个key ,使用 DJBHash 算法,标准差为:267989.4827787090310 个服务器,每个服务器 120 个虚拟节点,测试1000000 个key ,使用 DJBHash 算法,标准差为:161183.6918797928410 个服务器,每个服务器 140 个虚拟节点,测试1000000 个key ,使用 DJBHash 算法,标准差为:161183.6918797928410 个服务器,每个服务器 160 个虚拟节点,测试1000000 个key ,使用 DJBHash 算法,标准差为:161183.6918797928410 个服务器,每个服务器 180 个虚拟节点,测试1000000 个key ,使用 DJBHash 算法,标准差为:161183.6918797928410 个服务器,每个服务器 200 个虚拟节点,测试1000000 个key ,使用 DJBHash 算法,标准差为:161183.69187979284==============分隔==============10 个服务器,每个服务器 100 个虚拟节点,测试1000000 个key ,使用 JSHash 算法,标准差为:132226.5169169936310 个服务器,每个服务器 120 个虚拟节点,测试1000000 个key ,使用 JSHash 算法,标准差为:94827.3229823556810 个服务器,每个服务器 140 个虚拟节点,测试1000000 个key ,使用 JSHash 算法,标准差为:94827.3229823556810 个服务器,每个服务器 160 个虚拟节点,测试1000000 个key ,使用 JSHash 算法,标准差为:94827.3229823556810 个服务器,每个服务器 180 个虚拟节点,测试1000000 个key ,使用 JSHash 算法,标准差为:94827.3229823556810 个服务器,每个服务器 200 个虚拟节点,测试1000000 个key ,使用 JSHash 算法,标准差为:94827.32298235568==============分隔==============10 个服务器,每个服务器 100 个虚拟节点,测试1000000 个key ,使用 RSHash 算法,标准差为:72489.2568040257910 个服务器,每个服务器 120 个虚拟节点,测试1000000 个key ,使用 RSHash 算法,标准差为:60751.63760755754610 个服务器,每个服务器 140 个虚拟节点,测试1000000 个key ,使用 RSHash 算法,标准差为:30929.10810223922510 个服务器,每个服务器 160 个虚拟节点,测试1000000 个key ,使用 RSHash 算法,标准差为:20667.9082637793810 个服务器,每个服务器 180 个虚拟节点,测试1000000 个key ,使用 RSHash 算法,标准差为:14537.0071197616210 个服务器,每个服务器 200 个虚拟节点,测试1000000 个key ,使用 RSHash 算法,标准差为:19730.376174822417==============分隔==============10 个服务器,每个服务器 100 个虚拟节点,测试1000000 个key ,使用 SDBMHash 算法,标准差为:61024.4677486006410 个服务器,每个服务器 120 个虚拟节点,测试1000000 个key ,使用 SDBMHash 算法,标准差为:39616.9822172259910 个服务器,每个服务器 140 个虚拟节点,测试1000000 个key ,使用 SDBMHash 算法,标准差为:39577.4901680235410 个服务器,每个服务器 160 个虚拟节点,测试1000000 个key ,使用 SDBMHash 算法,标准差为:39540.5970617541410 个服务器,每个服务器 180 个虚拟节点,测试1000000 个key ,使用 SDBMHash 算法,标准差为:39512.0801780923710 个服务器,每个服务器 200 个虚拟节点,测试1000000 个key ,使用 SDBMHash 算法,标准差为:39480.806476058715==============分隔==============10 个服务器,每个服务器 100 个虚拟节点,测试1000000 个key ,使用 bernstein 算法,标准差为:154564.5581108424810 个服务器,每个服务器 120 个虚拟节点,测试1000000 个key ,使用 bernstein 算法,标准差为:154564.5448607150810 个服务器,每个服务器 140 个虚拟节点,测试1000000 个key ,使用 bernstein 算法,标准差为:154564.5448607150810 个服务器,每个服务器 160 个虚拟节点,测试1000000 个key ,使用 bernstein 算法,标准差为:154564.5448607150810 个服务器,每个服务器 180 个虚拟节点,测试1000000 个key ,使用 bernstein 算法,标准差为:154564.5448607150810 个服务器,每个服务器 200 个虚拟节点,测试1000000 个key ,使用 bernstein 算法,标准差为:154564.54486071508==============分隔==============10 个服务器,每个服务器 100 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:10297.25827587130210 个服务器,每个服务器 120 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:9278.56281974746310 个服务器,每个服务器 140 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:9603.4693730963710 个服务器,每个服务器 160 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:9576.9682050218810 个服务器,每个服务器 180 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:8341.96331806847410 个服务器,每个服务器 200 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:6953.414700706409==============分隔==============10 个服务器,每个服务器 100 个虚拟节点,测试1000000 个key ,使用 java 算法,标准差为:154447.999171242110 个服务器,每个服务器 120 个虚拟节点,测试1000000 个key ,使用 java 算法,标准差为:178426.978408535510 个服务器,每个服务器 140 个虚拟节点,测试1000000 个key ,使用 java 算法,标准差为:178426.978408535510 个服务器,每个服务器 160 个虚拟节点,测试1000000 个key ,使用 java 算法,标准差为:178426.978408535510 个服务器,每个服务器 180 个虚拟节点,测试1000000 个key ,使用 java 算法,标准差为:178426.978408535510 个服务器,每个服务器 200 个虚拟节点,测试1000000 个key ,使用 java 算法,标准差为:178426.9784085355==============进一步测试了FNH1 和 oneByone ==============10 个服务器,每个服务器 220 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:6647.21836560226210 个服务器,每个服务器 240 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:7060.63963108159210 个服务器,每个服务器 260 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:5204.91191087803110 个服务器,每个服务器 280 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:4229.26376571620310 个服务器,每个服务器 300 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:3894.35963927318910 个服务器,每个服务器 320 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:3409.75380342921510 个服务器,每个服务器 340 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:4094.819776253895310 个服务器,每个服务器 360 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:3763.94434071493710 个服务器,每个服务器 380 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:4245.54307480209210 个服务器,每个服务器 400 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:4066.490624604955410 个服务器,每个服务器 420 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:4226.43916317270610 个服务器,每个服务器 440 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:3895.017714978970610 个服务器,每个服务器 460 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:4233.940953768722510 个服务器,每个服务器 480 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:4194.4601559676310 个服务器,每个服务器 500 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:4034.790948735758310 个服务器,每个服务器 520 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:4361.70540041392510 个服务器,每个服务器 540 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:4174.96874239795910 个服务器,每个服务器 560 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:4165.40802323133710 个服务器,每个服务器 580 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:3415.39075363273810 个服务器,每个服务器 600 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:3191.808891522172410 个服务器,每个服务器 620 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:3004.501955399596710 个服务器,每个服务器 640 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:3099.859029052772710 个服务器,每个服务器 660 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2468.290298972144710 个服务器,每个服务器 680 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2067.775132842060410 个服务器,每个服务器 700 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2090.24998504963510 个服务器,每个服务器 720 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2188.975331062458710 个服务器,每个服务器 740 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2185.62187946588810 个服务器,每个服务器 760 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2255.01906865551810 个服务器,每个服务器 780 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2505.375221398982410 个服务器,每个服务器 800 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2176.665109749315410 个服务器,每个服务器 820 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2488.705285886619510 个服务器,每个服务器 840 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2389.84905381072110 个服务器,每个服务器 860 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:1843.266868904228910 个服务器,每个服务器 880 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2037.94817156864910 个服务器,每个服务器 900 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2015.858439970426210 个服务器,每个服务器 920 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:1838.252634977031710 个服务器,每个服务器 940 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2099.44504572041610 个服务器,每个服务器 960 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2201.57648061565210 个服务器,每个服务器 980 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2115.325625051613810 个服务器,每个服务器 1000 个虚拟节点,测试1000000 个key ,使用 oneByOneHash 算法,标准差为:2331.829539224512==============分隔==============10 个服务器,每个服务器 220 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:7181.89000194238510 个服务器,每个服务器 240 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:6296.05209635371510 个服务器,每个服务器 260 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:4785.6458289346910 个服务器,每个服务器 280 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:5079.12315267113810 个服务器,每个服务器 300 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:4880.02889335708710 个服务器,每个服务器 320 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:4342.53267114940610 个服务器,每个服务器 340 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:4346.43739170369310 个服务器,每个服务器 360 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:4876.86948769392410 个服务器,每个服务器 380 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:4011.07142793543410 个服务器,每个服务器 400 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3739.06659475329510 个服务器,每个服务器 420 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3656.79313059954210 个服务器,每个服务器 440 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3536.723059556685310 个服务器,每个服务器 460 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:2912.68776218804510 个服务器,每个服务器 480 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3105.506399929003710 个服务器,每个服务器 500 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3463.14827866206210 个服务器,每个服务器 520 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:2970.87074777749310 个服务器,每个服务器 540 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3166.053537134203510 个服务器,每个服务器 560 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3915.71500495120310 个服务器,每个服务器 580 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3311.01872540763510 个服务器,每个服务器 600 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:4274.614836450180510 个服务器,每个服务器 620 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:4227.95600733971710 个服务器,每个服务器 640 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:4031.246705425010510 个服务器,每个服务器 660 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3488.07798077967310 个服务器,每个服务器 680 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3719.455470898932610 个服务器,每个服务器 700 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:4043.848661856672610 个服务器,每个服务器 720 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3885.813814376597310 个服务器,每个服务器 740 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3534.08347383023810 个服务器,每个服务器 760 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3637.846890675856710 个服务器,每个服务器 780 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3217.735072997775710 个服务器,每个服务器 800 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3137.498366533439410 个服务器,每个服务器 820 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3145.79242799012410 个服务器,每个服务器 840 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3384.59953317966410 个服务器,每个服务器 860 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3044.010 个服务器,每个服务器 880 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:2831.60431557800810 个服务器,每个服务器 900 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:2585.568312769941310 个服务器,每个服务器 920 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:2366.11992510946110 个服务器,每个服务器 940 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:2438.514301782952310 个服务器,每个服务器 960 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:2979.57446626191910 个服务器,每个服务器 980 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3264.74409410599910 个服务器,每个服务器 1000 个虚拟节点,测试1000000 个key ,使用 FNVHash1 算法,标准差为:3468.0595438948276
从测试结果总结:
hash选择非常重要,有的hash算法标准差为几万,而且也不随虚拟节点增加变化。有可能这些算法设计的目的是解决hash冲突的,不是注重均匀散列分布的。或者是我使用的方式不对。
FNV1Hash 算法 和 oneByone 算法表现突出,进一步测试发现 oneByone 方差更小。在不考虑算法的执行效率前提下 oneByone算法是很好的选择。
zcj
还未添加个人签名 2019.10.12 加入
精神小伙
评论