一致性hash解决的问题

在解决分布式系统中负载均衡的问题时候可以使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡的作用。

但是普通的余数hash(hash(比如用户id)%服务器机器数)算法伸缩性很差,当新增或者下线服务器机器时候,用户id与服务器的映射关系会大量失效。一致性hash则利用hash环对其进行了改进。

一致性hash的特性

①,单调性

单调性(Monotonicity),单调性是指如果已经有一些请求通过哈希分派到了相应的服务器进行处理,又有新的服务器加入到系统中时候,应保证原有的请求可以被映射到原有的或者新的服务器中去,而不会被映射到原来的其它服务器上去。

②,分散性
一个用户的请求被路由到不同的服务器进行处理。好的哈希算法应尽量避免尽量降低分散性。 一致性hash具有很低的分散性
③,平衡性
致性hash可以做到每个服务器都进行处理请求,但是不能保证每个服务器处理的请求的数量大致相同,这里就要引入虚拟节点来解决这个问题

原文:https://blog.csdn.net/u011305680/article/details/79721030

参考: https://www.jianshu.com/p/e968c081f563

1、不带虚拟节点的

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

2、带虚拟节点的

  1. package hash;
  2.  
  3. import java.util.LinkedList;
  4. import java.util.List;
  5. import java.util.SortedMap;
  6. import java.util.TreeMap;
  7.  
  8. import org.apache.commons.lang.StringUtils;
  9.  
  10. /**
  11. * 带虚拟节点的一致性Hash算法
  12. */
  13. public class ConsistentHashingWithoutVirtualNode {
  14.  
  15. //待添加入Hash环的服务器列表
  16. private static String[] servers = {"192.168.0.0:111", "192.168.0.1:111", "192.168.0.2:111",
  17. "192.168.0.3:111", "192.168.0.4:111"};
  18.  
  19. //真实结点列表,考虑到服务器上线、下线的场景,即添加、删除的场景会比较频繁,这里使用LinkedList会更好
  20. private static List<String> realNodes = new LinkedList<String>();
  21.  
  22. //虚拟节点,key表示虚拟节点的hash值,value表示虚拟节点的名称
  23. private static SortedMap<Integer, String> virtualNodes = new TreeMap<Integer, String>();
  24.  
  25. //虚拟节点的数目,这里写死,为了演示需要,一个真实结点对应5个虚拟节点
  26. private static final int VIRTUAL_NODES = 5;
  27.  
  28. static{
  29. //先把原始的服务器添加到真实结点列表中
  30. for(int i=0; i<servers.length; i++)
  31. realNodes.add(servers[i]);
  32.  
  33. //再添加虚拟节点,遍历LinkedList使用foreach循环效率会比较高
  34. for (String str : realNodes){
  35. for(int i=0; i<VIRTUAL_NODES; i++){
  36. String virtualNodeName = str + "&&VN" + String.valueOf(i);
  37. int hash = getHash(virtualNodeName);
  38. System.out.println("虚拟节点[" + virtualNodeName + "]被添加, hash值为" + hash);
  39. virtualNodes.put(hash, virtualNodeName);
  40. }
  41. }
  42. System.out.println();
  43. }
  44.  
  45. //使用FNV1_32_HASH算法计算服务器的Hash值,这里不使用重写hashCode的方法,最终效果没区别
  46. private static int getHash(String str){
  47. final int p = 16777619;
  48. int hash = (int)2166136261L;
  49. for (int i = 0; i < str.length(); i++)
  50. hash = (hash ^ str.charAt(i)) * p;
  51. hash += hash << 13;
  52. hash ^= hash >> 7;
  53. hash += hash << 3;
  54. hash ^= hash >> 17;
  55. hash += hash << 5;
  56.  
  57. // 如果算出来的值为负数则取其绝对值
  58. if (hash < 0)
  59. hash = Math.abs(hash);
  60. return hash;
  61. }
  62.  
  63. //得到应当路由到的结点
  64. private static String getServer(String key){
  65. //得到该key的hash值
  66. int hash = getHash(key);
  67. // 得到大于该Hash值的所有Map
  68. SortedMap<Integer, String> subMap = virtualNodes.tailMap(hash);
  69. String virtualNode;
  70. if(subMap.isEmpty()){
  71. //如果没有比该key的hash值大的,则从第一个node开始
  72. Integer i = virtualNodes.firstKey();
  73. //返回对应的服务器
  74. virtualNode = virtualNodes.get(i);
  75. }else{
  76. //第一个Key就是顺时针过去离node最近的那个结点
  77. Integer i = subMap.firstKey();
  78. //返回对应的服务器
  79. virtualNode = subMap.get(i);
  80. }
  81. //virtualNode虚拟节点名称要截取一下
  82. if(StringUtils.isNotBlank(virtualNode)){
  83. return virtualNode.substring(0, virtualNode.indexOf("&&"));
  84. }
  85. return null;
  86. }
  87.  
  88. public static void main(String[] args){
  89. String[] keys = {"太阳", "月亮", "星星"};
  90. for(int i=0; i<keys.length; i++)
  91. System.out.println("[" + keys[i] + "]的hash值为" +
  92. getHash(keys[i]) + ", 被路由到结点[" + getServer(keys[i]) + "]");
  93. }
  94. }

一致性hash的实现的更多相关文章

  1. 对一致性Hash算法,Java代码实现的深入研究

    一致性Hash算法 关于一致性Hash算法,在我之前的博文中已经有多次提到了,MemCache超详细解读一文中"一致性Hash算法"部分,对于为什么要使用一致性Hash算法.一致性 ...

  2. 转载自lanceyan: 一致性hash和solr千万级数据分布式搜索引擎中的应用

    一致性hash和solr千万级数据分布式搜索引擎中的应用 互联网创业中大部分人都是草根创业,这个时候没有强劲的服务器,也没有钱去买很昂贵的海量数据库.在这样严峻的条件下,一批又一批的创业者从创业中获得 ...

  3. 一致性hash算法详解

    转载请说明出处:http://blog.csdn.net/cywosp/article/details/23397179     一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT) ...

  4. 探索c#之一致性Hash详解

    阅读目录: 使用场景 算法原理 虚拟节点 代码示例 使用场景 以Redis为例,当系统需要缓存的内容超过单机内存大小时,例如要缓存100G数据,单机内存仅有16G时.这时候就需要考虑进行缓存数据分片, ...

  5. 一致性hash算法简介

    一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简单哈希 ...

  6. 分布式缓存技术memcached学习(四)—— 一致性hash算法原理

    分布式一致性hash算法简介 当你看到“分布式一致性hash算法”这个词时,第一时间可能会问,什么是分布式,什么是一致性,hash又是什么.在分析分布式一致性hash算法原理之前,我们先来了解一下这几 ...

  7. 关于Memcached一致性hash的探究

    参考文章 http://blog.chinaunix.net/uid-20498361-id-4303232.html http://blog.csdn.net/kongqz/article/deta ...

  8. 一致性 hash 算法( consistent hashing )a

    一致性 hash 算法( consistent hashing ) 张亮 consistent hashing 算法早在 1997 年就在论文 Consistent hashing and rando ...

  9. Ceph剖析:数据分布之CRUSH算法与一致性Hash

    作者:吴香伟 发表于 2014/09/05 版权声明:可以任意转载,转载时务必以超链接形式标明文章原始出处和作者信息以及版权声明 数据分布是分布式存储系统的一个重要部分,数据分布算法至少要考虑以下三个 ...

  10. 一致性Hash算法

    from wikipedia 一致哈希 历史 1997年由MIT的Karger等在一篇学术论文中提出如何将“一致性Hash”应用于用户易变的分布式Web服务中.也可用于实现健壮缓存来减少大型Web应用 ...

随机推荐

  1. javascript:没有定义的变量和没有定义的属性

    1. 没有定义的变量 window.onload = function() { alert(a); // 报错: Uncaught ReferenceError: a is not defined / ...

  2. C# TreeView 拖拽节点到另一个容器Panel中简单实现

    C# TreeView 拖拽节点到另一个容器Panel中简单实现 用了这么久C#拖拽功能一直没有用到也就没用过,今天因为项目需要,领导特地给我简单讲解了下拖拽功能,真是的大师讲解一点通啊.特地写一篇博 ...

  3. Go学习笔记(四)Go自动化测试框架

    上篇Go学习笔记(三)Go语言学习 Go自动化测试非常简单,在结合VSCode的,让测试完全自动化 一 .编辑器下测试 1.测试代码以xxx_test.go方式命名 2.测试函数要以 func Tes ...

  4. win10 安装mysql

    现在mysql压缩包:https://downloads.mysql.com/archives/community/ 在目录下新建data文件夹,my.ini文件,内容如下: [mysqld] bas ...

  5. 添加ll命令

    $ vim ~/.bashrcalias ll='ls -l'   #加入此行 ps:加入后肯能无法当场起作用,执行该句: source ~/.bashrc

  6. Nestjs 增加全局前缀

    文档 const app = await NestFactory.create(AppModule); app.setGlobalPrefix('v1'); // http://localhost:5 ...

  7. git最佳实践之feature和hotfix分支

    先来复习一波,git的最佳分支管理流程: 再简单复习各个分支: master: 主分支,主要用来版本发布. develop:日常开发分支,该分支正常保存了开发的最新代码. feature:具体的功能开 ...

  8. 带你开发一款给Apk中自动注入代码工具icodetools(完善篇)【申明:来源于网络】

    带你开发一款给Apk中自动注入代码工具icodetools(完善篇)[申明:来源于网络] 带你开发一款给Apk中自动注入代码工具icodetools(完善篇):http://blog.csdn.net ...

  9. centos6多实例安装mysql

    基本环境:setenforce 0service iptables stop yum install cmake libaio-devel ncurses-devel -yyum install gc ...

  10. 洛谷P3178 树上操作 [HAOI2015] 树链剖分

    正解:树链剖分+线段树 解题报告: 传送门! 树链剖分+线段树算是基操了趴,,, 就无脑码码码,没有任何含金量,不需要动脑子,然后码量其实也不大,就很爽 比树剖的板子还要板子一些hhhhh 放下代码就 ...