龙空技术网

负载均衡之缓存路由(一致性Hash)算法Java实现

hiahia0715 506

前言:

目前看官们对“路由算法题目”可能比较重视,各位老铁们都想要分析一些“路由算法题目”的相关内容。那么小编同时在网络上收集了一些有关“路由算法题目””的相关资讯,希望兄弟们能喜欢,各位老铁们一起来了解一下吧!

负载均衡之缓存路由(一致性Hash)算法Java实现

  分布式系统中负载均衡的问题时候可以使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡的作用。比如说分布式缓存,既然是缓存,就没有必要去做一个所有机器上的数据都完全一样的缓存集群,而是应该设计一套好的缓存路由工具类,所以一致性Hash算法就因此而诞生了。

  衡量一个一致性Hash算法最重要的两个特征:

①平衡性:平衡性是指哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。

②单调性:单调性是指如果已经有一些数据通过哈希分配到了相应的机器上,又有新的机器加入到系统中。哈希的结果应能够保证原有的数据要么还是呆在它所在的机器上不动,要么被迁移到新的机器上,而不会迁移到旧的其他机器上。

  业界常用的两种一致性Hash算法,一种是不带虚拟节点的Hash算法,另外一种是带虚拟节点的Hash算法。

  下面的代码就是不带虚拟节点的一致性Hash算法,原理稍后分析:

  首先,针对平衡性,我们需要选择一个好的Hash函数,我们选择的Hash算法是业界内比较出名的Time33 Hash算法,这个你们可以百度一下。但是Time33 Hash算法有一个弊端,那就是对于两个key差不多的字符串来说,他们生成的Hash值很接近,所以我们的解决办法就是在生成Hash值之前先用MD5算法取一次信息指纹。

  nodeMap是用来保存服务器节点信息的SortedMap(key是hash值,value是服务器节点信息); servers是服务器的配置信息;使用static静态代码块初始化nodeMap保存节点信息。

  缓存路由算法是核心代码,大概思想是先计算key的hash值,然后用hash值找到nodeMap中的所有键值大于该hash值的键值对,如果找到,取键值对最小的那个键值对的值作为路由结果;如果没有找到键值对的键大于该hash值的键值对,那么就取nodeMap里键值对的键最小的那个值作为路由结果。

  接下来,我们使用UUID生成随机字符串测试一下吧,测试结果如下:

  但是这种不带虚拟节点的路由算法有个问题,在增减机器时会使旧的数据大量“失效”,也称为命中率下降。

  于是我们选择把一个机器分为很多个虚拟节点,并且使这些虚拟节点交叉的分散在一个hash环上,经过改良后的代码如下:

  虚拟节点的大致思想之这样的,使用真实节点+"&"+序号(序号的范围是0到单台服务器所需的虚拟节点个数VIRTUAL_NODE_NUM)作为虚拟节点的值,核心代码如上面截图所示。

  接下来,我们还是使用UUID生成随机字符串测试一下吧,测试结果如下:

  好的,大功告成,以上就是关于一致性Hash路由算法的全部内容。PS:以上代码有删减,仅提取了其中的核心代码。由于头条平台的代码排版有问题,所以只能截图,如果感兴趣,同名公众号同名文章里有文字版的。如果喜欢我的内容的话,欢迎转发,谢谢。

  欢迎大家关注"Java架构师养成记",不定期分享各类面试题、踩坑经历。

标签: #路由算法题目