一致性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. TIJ -- 吐司BlockingQueue

    1. 吐司BlockingQueue 考虑下面这个使用BlockingQueue的示例.有一台机器具有三个任务:一个制作吐司,一个给吐司抹黄油,另一个在抹过黄油的吐司上吐果酱.我们可以通过各个处理过程 ...

  2. Linux下查看设设置时间date命令

    查看时间 # date "+%Y_%m_%d  %H-%M-%S" 设置时间 #date -s "2018-05-17 09:51:50" //写入到硬件时钟 ...

  3. NB-Iot的应用领域、覆盖范围,是什么

    该部分分享的是物联网各垂直应用领域里,NB-IoT技术的部署,看看适合NB-IoT技术的垂直应用场景有哪些?垂直应用服务商又该如何部署? 1 NB-IoT适合的垂直应用场景有哪些? 2 NB-IoT垂 ...

  4. threding模块的其他用法

    import threading import time def func(n): time.sleep(0.5) n += 1 print(n, threading.current_thread() ...

  5. 阿里天池的新任务(简单)(KMP统计子串出现的次数)

    阿里“天池”竞赛平台近日推出了一个新的挑战任务:对于给定的一串 DNA 碱基序列 tt,判断它在另一个根据规则生成的 DNA 碱基序列 ss 中出现了多少次. 输出格式 输出一个整数,为 tt 在 s ...

  6. wamp 进入到项目中找不到localhost

    重点在 www 目录的 index.php 里面,把里面没有第一句没有被注释的话: $suppress_localhost = true; 改成 $suppress_localhost = false ...

  7. Educational Codeforces Round 4

    612A - The Text Splitting    20171121 简单字符串处理题 #include<stdlib.h> #include<stdio.h> #inc ...

  8. 有趣的JavaScript隐式类型转换

    JavaScript的数据类型是非常弱的(不然不会叫它做弱类型语言了)!在使用算术运算符时,运算符两边的数据类型可以是任意的,比如,一个字符串可以和数字相加.之所以不同的数据类型之间可以做运算,是因为 ...

  9. linux命令sync,shutdown

    1.数据同步写入磁盘: sync 输入sync,那举在内存中尚未被更新的数据,就会被写入硬盘中 hling@hling:~$ sync   2.惯用的关机指令:shutdown 实例:

  10. Android开发网【申明:来源于网络】

    Android开发网[申明:来源于网络] 地址:http://www.jizhuomi.com/android/video/