哈希hash

hash的意思是散列,目的是将一组输入的数据均匀的分开、打散,往往用来配合路由算法做负载均衡,多用在分布式系统中。比如memcached,它只提供了K V的存储、读取,如果使用了多台memcache做一个“逻辑集群”,就需要客户端做“路由算法”,来保证数据均匀的进去,然后能“原路”拿出来。

常规哈希取模

常规哈希,往往结合取模运算,以便将请求转发到后端的服务器上,如下图:

第一步使用hash算法,将请求“打散”得到一个整数(比如传递过来一个请求,使用jdk类库的hash对某个参数做计算),第二步将得到的参数对后端的服务器台数取模,以上图为例,假设有三台服务器,那么id分别为1~6的请求会被转发到1,2,0,1,2,0,上,不管请求id数是多少,总是这么周而复始的转发。

假设上面是个缓存系统,以上请求为set请求,在服务器数量不变的情况下,对同样的id做get请求,由于采用同样的hash算法,那么肯定能原路找到对应的key值。这个算法简单,而且数据分散的比较均匀。

如果系统访问量突增,为了扩容加了一台机器,编号为3,此时有了4台机器,采用同样的算法再去get请求会如何?比如id=6,这个时候 6%4=2,我们知道set时值其实放进了索引为0的机器,这个时候就get不到了。这就是上面算法的弊端,在增减机器时会使旧的数据大量“失效”,也就是命中率下降。

不带虚拟节点的一致性哈希算法

为了解决以上问题,聪明的人发明了一致性哈希算法。思路是这样,hash算法出来的整数有个范围,我们在这个范围内布置三台服务器(范围具体是多少看前面的hash算法)。假设hash的范围是1~300,每台负责一段范围内的请求,比如一台负责(1~100],一台负责(100~200],一台负责(200~1]。这三台server首尾相接覆盖/闭环了所有请求,称为哈希环,如下图:

如何实现一台服务器接收一个范围的请求?这个时候不用取模了,而是将server也按照hash算法计算一个id值,比如按照他们的ip+port+name拼成的串计算,假设正好分别是 1,100,200,将他们放进一个treeMap里,Map<Integer,Node> ,其中Node代表server节点,是自定义的数据结构,比如是一个类,包含ip,port,name等属性。我们的例子中,map里包含三个元素。

一个请求过来,hash得到的值必属于这三个server的范围,比如一个请求id=N,那么从map里get(N)去找server,找到直接转发,找不到进行如下运算:treemap里有个关键的api,tailMap(),这个接口能够返回id比N大的map的子集,然后取子集的第一个节点,就是id=100的节点,通常称为顺时针查找

 //得到应当路由到的结点(示例代码用String代表的节点)private static String getServer(String key) {//得到该key的hash值int hash = getHash(key);//得到大于该Hash值的所有MapSortedMap<Integer, String> subMap = sortedMap.tailMap(hash);if(subMap.isEmpty()){//如果没有比该key的hash值大的,则从第一个node开始Integer i = sortedMap.firstKey();//返回对应的服务器return sortedMap.get(i);}else{//第一个Key就是顺时针过去离node最近的那个结点Integer i = subMap.firstKey();//返回对应的服务器return subMap.get(i);}}

当然如果子集为空,这意味着N>200,就取整个map的第一个节点,完成闭环。

分析:从实现可以看出,如果一个节点挂了,他的流量会顺时针(逆时针实现也是一样的)“导流”到下一个节点,其他节点不受影响。假如有100台服务器,一台挂了,其他99台都能正常命中!这个算法比简单的取模好了很多。

不过这里仍有个问题,假设各台服务器性能差不多,此时流量突增,一台server由于流量过载而挂掉,那么它的下一台因为承载了2倍的流量,很有可能也会挂掉,依此类推,最后所有的节点都会挂掉,造成“雪崩”!

因此正常情况下,我们往往采用带虚拟节点的一致性哈希算法(不特别说明的一致性哈希算法一般都是指的带虚拟节点的算法)。

带虚拟节点的一致性哈希算法

带虚拟节点的一致性哈希算法是为了解决不带虚拟节点算法的雪崩问题,虚拟节点也称为分片。在上一步的基础上理解虚拟节点是非常容易的。“虚拟”节点是server的副本、分身,每个虚拟节点存储的server信息还是后面的物理地址,只不过每个server由一台变成了多台,这个时候往treeMap放节点时往往这么做:

for(i=1  -->  N) // N为每个server对应的分片数量
{Map.put(hash(ip+port+name+i),node) // 所有虚拟节点放进去
}

这个for循环外面还会有个循环,处理所有server node

由于每个server的ip,name不同,所以以上拼串hash后的值碰撞的概率是很小的,这样所有的虚拟节点也会离散的分布到环上,形成的hash环如下图,同样颜色的虚拟节点同属于一个server。

这个时候如果红颜色的server挂了,它的虚拟节点负责的范围会分别导航到下一个虚拟节点上,这些虚拟节点分别属于不同的server,就避免了流量全部导流到一台机器上。由于流量被均摊了,有效的减少了雪崩发生的概率。(理论上仍存在虚拟节点后面的虚拟节点属于同一个server的情况,但是当虚拟节点非常多时,这个概率是非常小的,而且这个分片数量是自定义的,往往设置几百个)。

只要是hash算法,就有哈希碰撞的可能性,在增加server时,计算后的虚拟节点跟其他server的虚拟节点重复的话,也会导致部分缓存失效(可以通过算法改良)。

综上,一致性哈希算法并不是强一致性,也不是高可用方案,如果server挂了数据丢了就是丢了,除非有恢复手段,它只是一种减少由扩缩容引起的命中率下降的手段。

代码可参考如下链接

https://blog.csdn.net/WANGYAN9110/article/details/70185652

https://blog.csdn.net/u010558660/article/details/52767218
————————————————
版权声明:本文为CSDN博主「飞出银河系」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/flyfeifei66/article/details/82458618

Java一致性Hash算法的实现相关推荐

  1. java一致性hash api_一致性哈希算法学习及JAVA代码实现分析

    戳上面的蓝字关注我们哦! 本文作者:hapjin 欢迎点击下方阅读原文 1,对于待存储的海量数据,如何将它们分配到各个机器中去?---数据分片与路由 当数据量很大时,通过改善单机硬件资源的纵向扩充方式 ...

  2. 一致性hash算法和redis集群动态数据存储

    记录:对一致性Hash算法,Java代码实现的深入研究链接地址: http://www.cnblogs.com/xrq730/p/5186728.html 全部来自: https://mp.weixi ...

  3. java 一致性hash算法 均衡分发_负载均衡-基础-一致性哈希算法及java实现

    1 /** 2 * 一致性hash 的java 实现3 *@authorluoqiang4 * @data 2016/11/085 */ 6 public classConsistencyHash { ...

  4. java 一致性hash算法 均衡分发_Dubbo一致性哈希负载均衡的源码和Bug,了解一下?...

    本文是对于Dubbo负载均衡策略之一的一致性哈希负载均衡的详细分析.对源码逐行解读.根据实际运行结果,配以丰富的图片,可能是东半球讲一致性哈希算法在Dubbo中的实现最详细的文章了. 文中所示源码,没 ...

  5. Java时间轮算法的实现

    考虑这样一个场景,现在有5000个任务,要让这5000个任务每隔5分中触发某个操作,怎么去实现这个需求.大部分人首先想到的是使用定时器,但是5000个任务,你就要用5000个定时器,一个定时器就是一个 ...

  6. fp增长树java实现_FP-Tree算法的实现(Java版)

    在关联规则挖掘领域最经典的算法法是Apriori,其致命的缺点是需要多次扫描事务数据库.于是人们提出了各种裁剪(prune)数据集的方法以减少I/O开支,韩嘉炜老师的FP-Tree算法就是其中非常高效 ...

  7. knn算法java版_KNN算法的实现详解

    #!/usr/bin/env python #-*-coding:utf-8-*- #knn 的具体实现 import csv import random import math import ope ...

  8. Redis集群一致性Hash效果的代码演示

    在微服务领域,使用Redis做缓存可并不是一件容易的事情. 像新浪.推特这样的应用,许许多多的热点数据全都存放在Redis这一层,打到DB层的请求并不多,可以说非常依赖缓存了.如果缓存挂掉,流量全部穿 ...

  9. 「分布式专题」分布式系统中一致性hash算法

    近年来B2C.O2O等商业概念的提出和移动端的发展,使得分布式系统流行了起来.分布式系统相对于单系统,解决了流量大.系统高可用和高容错等问题.功能强大也意味着实现起来需要更多技术的支持.例如系统访问层 ...

最新文章

  1. 每日一皮:为这位姑娘的回答鼓掌!
  2. 如何将加密PDF转换成Word文档
  3. [HTML5amp;CSS3]Transform具体解释
  4. python学了真的很有用吗-python学了真的很有用吗?当然!赶紧学,不学后悔!
  5. mysql触发器联机删除_mysql触发器删除实例1
  6. php加skplayer,织梦dedecms怎么整合添加ckplayer播放器支持flv,mp4等播放功能
  7. 微商的十种实用推广方法
  8. RS485MODBUS转PROFINET网关配置-科隆OPTIFLUX7000MODBUS通信协议电磁流量计接入西门子PLC S7-1500PROFINET以太网通讯网络配置方法
  9. 荣耀9igoogle模式_初学者:如何从iGoogle切换回纯Google主页
  10. 论文笔记:TrafficPredict: Trajectory Prediction for Heterogeneous Traffic-Agents
  11. 入门计算机的粗略学习-Day13
  12. react redux mysql_实现React-redux的基本功能
  13. vb html ie弹出窗口,vb操作ie浏览器
  14. php 文字转unicode,php汉字如何转unicode
  15. 计算机无法识别3.0u盘启动,USB3.0接口的解决方案无法识别U盘
  16. linux修改时间写入cmos,解析Linux操作系统修改时间
  17. 一图了解券商IT战略咨询方法论
  18. akoj-1291-决战21点(C#)
  19. 站长便民小工具引流网站源码_站长引流工具箱
  20. 地平线黎明时分dlc评测_我从第一个玩法中学到的地平线零黎明的提示

热门文章

  1. 信息系统项目管理师-人力资源管理知识点
  2. 《大话数据结构》第2章 算法基础 2.8 函数的渐近增长
  3. 磁金融宣布完成1.2亿元B轮融资,宽带资本领投
  4. CF1060D Social Circles
  5. Android Resources
  6. Sqlite基础及其与SQLServer语法差异
  7. 模式识别之基础---常用分类算法特性归纳
  8. 笔记本Wifi连接出现“设置与网络连接不匹配”的解决方法
  9. 中小企业如何用在线CRM留住客户
  10. 【中文】Joomla1.7扩展介绍之JoomSEF Free (搜索引擎友好)