【策略】一致性Hash算法(Hash环)的java代码实现

简介: 【一】一致性hash算法,基本实现分布平衡。 1 package org.ehking.quartz.curator; 2 3 import java.util.SortedMap; 4 import java.

【一】一致性hash算法,基本实现分布平衡。

 1 package org.ehking.quartz.curator;
 2 
 3 import java.util.SortedMap;
 4 import java.util.TreeMap;
 5 
 6 public class ConsistentHashingWithoutVirtualNode {
 7     /**
 8            * 待添加入Hash环的服务器列表
 9           */
10          private static String[] servers = {"192.168.0.0:111", "192.168.0.1:111", "192.168.0.2:111",
11                 "192.168.0.3:111", "192.168.0.4:111"};
12      
13        /**
14       * key表示服务器的hash值,value表示服务器的名称
15          */
16          private static SortedMap<Integer, String> sortedMap = 
17              new TreeMap<Integer, String>();
18         
19      /**
20       * 程序初始化,将所有的服务器放入sortedMap中
21      */
22      static
23   {
24       for (int i = 0; i < servers.length; i++)
25        {
26           int hash = getHash(servers[i]);
27           System.out.println("[" + servers[i] + "]加入集合中, 其Hash值为" + hash);
28            sortedMap.put(hash, servers[i]);
29        }
30         System.out.println();
31     }
32      
33      /**
34       * 使用FNV1_32_HASH算法计算服务器的Hash值,这里不使用重写hashCode的方法,最终效果没区别 
35      */
36      private static int getHash(String str)
37      {
38          final int p = 16777619;
39          int hash = (int)2166136261L;
40          for (int i = 0; i < str.length(); i++)
41         hash = (hash ^ str.charAt(i)) * p;
42         hash += hash << 13;
43        hash ^= hash >> 7;
44        hash += hash << 3;
45       hash ^= hash >> 17;
46         hash += hash << 5;
47          
48         // 如果算出来的值为负数则取其绝对值
49         if (hash < 0)
50             hash = Math.abs(hash);
51          return hash;
52      }
53    
54      /**
55       * 得到应当路由到的结点
56       */
57      private static String getServer(String node)
58      {
59          // 得到带路由的结点的Hash值
60          int hash = getHash(node);
61         // 得到大于该Hash值的所有Map
62          SortedMap<Integer, String> subMap = 
63                  sortedMap.tailMap(hash);
64          // 第一个Key就是顺时针过去离node最近的那个结点
65         Integer i = subMap.firstKey();
66          // 返回对应的服务器名称
67        return subMap.get(i);
68      }
69     
70      public static void main(String[] args)
71     {
72          String[] nodes = {"127.0.0.1:1111", "221.226.0.1:2222", "10.211.0.1:3333"};
73        for (int i = 0; i < nodes.length; i++)
74            System.out.println("[" + nodes[i] + "]的hash值为" + 
75                     getHash(nodes[i]) + ", 被路由到结点[" + getServer(nodes[i]) + "]");
76     }
77 }
View Code

【二】借助虚拟节点,实现分布平衡的hash算法

  1 package org.ehking.quartz.curator;
  2 
  3 import java.util.ArrayList;
  4 import java.util.HashMap;
  5 import java.util.LinkedList;
  6 import java.util.List;
  7 import java.util.Set;
  8 import java.util.SortedMap;
  9 import java.util.TreeMap;
 10 import java.util.UUID;
 11 
 12 public class ConsistentHashingWithVirtualNode {
 13     /**
 14      * 待添加入Hash环的服务器列表
 15       */
 16     private static String[] servers = { "192.168.0.0:111","192.168.0.1:111", "192.168.0.2:111"};
 17    
 18    /**
 19       * 真实结点列表,考虑到服务器上线、下线的场景,即添加、删除的场景会比较频繁,这里使用LinkedList会更好
 20      */
 21    private static List<String> realNodes = new LinkedList<String>();
 22    /**
 23     * 虚拟节点,key表示虚拟节点的hash值,value表示虚拟节点的名称
 24     */
 25    private static SortedMap<Integer, String> virtualNodes = 
 26            new TreeMap<Integer, String>();
 27     
 28     /**
 29       * 虚拟节点的数目,这里写死,为了演示需要,一个真实结点对应5个虚拟节点
 30     */
 31      private static final int VIRTUAL_NODES = 1000;
 32    
 33   static
 34   {
 35         // 先把原始的服务器添加到真实结点列表中
 36          for (int i = 0; i < servers.length; i++)
 37              realNodes.add(servers[i]);
 38          
 39         // 再添加虚拟节点,遍历LinkedList使用foreach循环效率会比较高
 40          for (String str : realNodes)
 41          {
 42              for (int i = 0; i < VIRTUAL_NODES; i++)
 43              {
 44                String virtualNodeName = str + "&&VN" + String.valueOf(i);
 45                  int hash = getHash(virtualNodeName);
 46                  System.out.println("虚拟节点[" + virtualNodeName + "]被添加, hash值为" + hash);
 47                 virtualNodes.put(hash, virtualNodeName);
 48             }
 49          }
 50          System.out.println();
 51    }
 52    
 53      /**
 54       * 使用FNV1_32_HASH算法计算服务器的Hash值,这里不使用重写hashCode的方法,最终效果没区别 
 55       */
 56      private static int getHash(String str)
 57      {
 58          final int p = 16777619;
 59         int hash = (int)2166136261L;
 60         for (int i = 0; i < str.length(); i++)
 61             hash = (hash ^ str.charAt(i)) * p;
 62           hash += hash << 13;
 63         hash ^= hash >> 7;
 64         hash += hash << 3;
 65         hash ^= hash >> 17;
 66         hash += hash << 5;
 67        
 68         // 如果算出来的值为负数则取其绝对值
 69          if (hash < 0)
 70              hash = Math.abs(hash);
 71          return hash;
 72      }
 73     
 74      /**
 75       * 得到应当路由到的结点
 76       */
 77      private static String getServer(String node)
 78      {
 79          // 得到带路由的结点的Hash值
 80          int hash = getHash(node);
 81          // 得到大于该Hash值的所有Map
 82          SortedMap<Integer, String> subMap = 
 83                  virtualNodes.tailMap(hash);
 84          Integer i=null;
 85          String virtualNode = null;
 86          if(subMap==null||subMap.size()==0){
 87              i=virtualNodes.firstKey();
 88              virtualNode=virtualNodes.get(i);
 89          }else{
 90               i = subMap.firstKey();
 91               virtualNode= subMap.get(i);
 92          }
 93          // 第一个Key就是顺时针过去离node最近的那个结点
 94        
 95          // 返回对应的虚拟节点名称,这里字符串稍微截取一下
 96          return virtualNode.substring(0, virtualNode.indexOf("&&"));
 97      }
 98      
 99      public static void main(String[] args)
100      {
101         
102         HashMap<String,Integer> map=new HashMap<String, Integer>(); 
103          List<String> id=new ArrayList<String>();
104          for(int i=0;i<1000;i++){
105              id.add(UUID.randomUUID().toString().replace("-", ""));
106              //id.add("adasfdsafdsgfdsagdsafdsafdsaf"+i);
107          }         
108          for (int i = 0; i < id.size(); i++){
109              String aString=getServer(id.get(i));
110              Integer aInteger=map.get(aString);
111              if(aInteger==null){
112                  map.put(aString,1);
113              }else{
114                  map.put(aString, aInteger+1);
115              }
116          }
117          Set<String> set= map.keySet();
118         for(String a:set){
119             System.out.println("节点【"+a+"】分配到元素个数为==>"+map.get(a));
120         }
121     }
122  }
View Code

 

相关文章
|
16天前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
25 0
|
21天前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
47 24
|
2天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
37 2
|
17天前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
54 5
|
17天前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
45 5
|
15天前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
18天前
|
运维 Java 编译器
Java 异常处理:机制、策略与最佳实践
Java异常处理是确保程序稳定运行的关键。本文介绍Java异常处理的机制,包括异常类层次结构、try-catch-finally语句的使用,并探讨常见策略及最佳实践,帮助开发者有效管理错误和异常情况。
61 4
|
19天前
|
Java API 开发者
Java中的Lambda表达式:简洁代码的利器####
本文探讨了Java中Lambda表达式的概念、用途及其在简化代码和提高开发效率方面的显著作用。通过具体实例,展示了Lambda表达式如何在Java 8及更高版本中替代传统的匿名内部类,使代码更加简洁易读。文章还简要介绍了Lambda表达式的语法和常见用法,帮助开发者更好地理解和应用这一强大的工具。 ####
|
22天前
|
监控 算法 Java
Java虚拟机垃圾回收机制深度剖析与优化策略####
【10月更文挑战第21天】 本文旨在深入探讨Java虚拟机(JVM)中的垃圾回收机制,揭示其工作原理、常见算法及参数调优技巧。通过案例分析,展示如何根据应用特性调整GC策略,以提升Java应用的性能和稳定性,为开发者提供实战中的优化指南。 ####
36 5
|
23天前
|
Java API Maven
商汤人像如何对接?Java代码如何写?
商汤人像如何对接?Java代码如何写?
34 5