一致性hash算法_(图文案例)一致性哈希算法详解 一点课堂(多岸教育)

一致性Hash算法

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

算法的具体原理这里再次贴上:

先构造一个长度为2^32的整数环(这个环被称为一致性Hash环),根据节点名称的Hash值(其分布为[0, 2^32-1])将服务器节点放置在这个Hash环上,然后根据数据的Key值计算得到其Hash值(其分布也为[0, 2^32-1]),接着在Hash环上顺时针查找距离这个Key值的Hash值最近的服务器节点,完成Key到服务器的映射查找。

这种算法解决了普通余数Hash算法伸缩性差的问题,可以保证在上线、下线服务器的情况下尽量有多的请求命中原来路由到的服务器。

当然,万事不可能十全十美,一致性Hash算法比普通的余数Hash算法更具有伸缩性,但是同时其算法实现也更为复杂,本文就来研究一下,如何利用Java代码实现一致性Hash算法。在开始之前,先对一致性Hash算法中的几个核心问题进行一些探究。

数据结构的选取

一致性Hash算法最先要考虑的一个问题是:构造出一个长度为2^32的整数环,根据节点名称的Hash值将服务器节点放置在这个Hash环上。

那么,整数环应该使用何种数据结构,才能使得运行时的时间复杂度最低?首先说明一点,关于时间复杂度,常见的时间复杂度与时间效率的关系有如下的经验规则:

O(1) < O(log2N) < O(n) < O(N * logN) < O(N^2) < O(N^3) < 2^N < 3^N < N!

一般来说,前四个效率比较高,中间两个差强人意,后三个比较差(只要N比较大,这个算法就动不了了)。OK,继续前面的话题,应该如何选取数据结构,我认为有以下几种可行的解决方案。

1、解决方案一:排序+List

我想到的第一种思路是:算出所有待加入数据结构的节点名称的Hash值放入一个数组中,然后使用某种排序算法将其从小到大进行排序,最后将排序后的数据放入List中,采用List而不是数组是为了结点的扩展考虑。

之后,待路由的结点,只需要在List中找到第一个Hash值比它大的服务器节点就可以了,比如服务器节点的Hash值是[0,2,4,6,8,10],带路由的结点是7,只需要找到第一个比7大的整数,也就是8,就是我们最终需要路由过去的服务器节点。

如果暂时不考虑前面的排序,那么这种解决方案的时间复杂度:

(1)最好的情况是第一次就找到,时间复杂度为O(1)

(2)最坏的情况是最后一次才找到,时间复杂度为O(N)

平均下来时间复杂度为O(0.5N+0.5),忽略首项系数和常数,时间复杂度为O(N)。

但是如果考虑到之前的排序,我在网上找了张图,提供了各种排序算法的时间复杂度:

6e85907b22c0793c5fa13c698f62e0c2.png

2、解决方案二:遍历+List

既然排序操作比较耗性能,那么能不能不排序?可以的,所以进一步的,有了第二种解决方案。

解决方案使用List不变,不过可以采用遍历的方式:

(1)服务器节点不排序,其Hash值全部直接放入一个List中

(2)带路由的节点,算出其Hash值,由于指明了”顺时针”,因此遍历List,比待路由的节点Hash值大的算出差值并记录,比待路由节点Hash值小的忽略

(3)算出所有的差值之后,最小的那个,就是最终需要路由过去的节点

在这个算法中,看一下时间复杂度:

1、最好情况是只有一个服务器节点的Hash值大于带路由结点的Hash值,其时间复杂度是O(N)+O(1)=O(N+1),忽略常数项,即O(N)

2、最坏情况是所有服务器节点的Hash值都大于带路由结点的Hash值,其时间复杂度是O(N)+O(N)=O(2N),忽略首项系数,即O(N)

所以,总的时间复杂度就是O(N)。其实算法还能更改进一些:给一个位置变量X,如果新的差值比原差值小,X替换为新的位置,否则X不变。这样遍历就减少了一轮,不过经过改进后的算法时间复杂度仍为O(N)。

总而言之,这个解决方案和解决方案一相比,总体来看,似乎更好了一些。

3、解决方案三:二叉查找树

抛开List这种数据结构,另一种数据结构则是使用二叉查找树。

当然我们不能简单地使用二叉查找树,因为可能出现不平衡的情况。平衡二叉查找树有AVL树、红黑树等,这里使用红黑树,选用红黑树的原因有两点:

1、红黑树主要的作用是用于存储有序的数据,这其实和第一种解决方案的思路又不谋而合了,但是它的效率非常高

2、JDK里面提供了红黑树的代码实现TreeMap和TreeSet

另外,以TreeMap为例,TreeMap本身提供了一个tailMap(K fromKey)方法,支持从红黑树中查找比fromKey大的值的集合,但并不需要遍历整个数据结构。

使用红黑树,可以使得查找的时间复杂度降低为O(logN),比上面两种解决方案,效率大大提升。

为了验证这个说法,我做了一次测试,从大量数据中查找第一个大于其中间值的那个数据,比如10000数据就找第一个大于5000的数据(模拟平均的情况)。看一下O(N)时间复杂度和O(logN)时间复杂度运行效率的对比:

因为再大就内存溢出了,所以只测试到4000000数据。可以看到,数据查找的效率,TreeMap是完胜的,其实再增大数据测试也是一样的,红黑树的数据结构决定了任何一个大于N的最小数据,它都只需要几次至几十次查找就可以查到。

当然,明确一点,有利必有弊,根据我另外一次测试得到的结论是,为了维护红黑树,数据插入效率TreeMap在三种数据结构里面是最差的,且插入要慢上5~10倍。

Hash值重新计算

服务器节点我们肯定用字符串来表示,比如”192.168.1.1″、”192.168.1.2″,根据字符串得到其Hash值,那么另外一个重要的问题就是Hash值要重新计算,这个问题是我在测试String的hashCode()方法的时候发现的,不妨来看一下为什么要重新计算Hash值:

/*** String的hashCode()方法运算结果查看* @author 哓哓**/public class StringHashCodeTest { public static void main(String[] args) { System.out.println("192.168.0.0:111的哈希值:" + "192.168.0.0:1111".hashCode()); System.out.println("192.168.0.1:111的哈希值:" + "192.168.0.1:1111".hashCode()); System.out.println("192.168.0.2:111的哈希值:" + "192.168.0.2:1111".hashCode()); System.out.println("192.168.0.3:111的哈希值:" + "192.168.0.3:1111".hashCode()); System.out.println("192.168.0.4:111的哈希值:" + "192.168.0.4:1111".hashCode()); }}

我们在做集群的时候,集群点的IP以这种连续的形式存在是很正常的。看一下运行结果为:

192.168.0.0:111的哈希值:1845870087192.168.0.1:111的哈希值:1874499238192.168.0.2:111的哈希值:1903128389192.168.0.3:111的哈希值:1931757540192.168.0.4:111的哈希值:1960386691

这个就问题大了,[0,2^32-1]的区间之中,5个HashCode值却只分布在这么小小的一个区间,什么概念?[0,2^32-1]中有4294967296个数字,而我们的区间只有122516605,从概率学上讲这将导致97%待路由的服务器都被路由到”192.168.0.1″这个集群点上,简直是糟糕透了!

另外还有一个不好的地方:规定的区间是非负数,String的hashCode()方法却会产生负数(不信用”192.168.1.0:1111″试试看就知道了)。不过这个问题好解决,取绝对值就是一种解决的办法。

综上,String重写的hashCode()方法在一致性Hash算法中没有任何实用价值,得找个算法重新计算HashCode。这种重新计算Hash值的算法有很多,比如CRC32_HASH、FNV1_32_HASH、KETAMA_HASH等,其中KETAMA_HASH是默认的MemCache推荐的一致性Hash算法,用别的Hash算法也可以,比如FNV1_32_HASH算法的计算效率就会高一些。

一致性Hash算法实现版本1:不带虚拟节点

使用一致性Hash算法,尽管增强了系统的伸缩性,但是也有可能导致负载分布不均匀,解决办法就是使用虚拟节点代替真实节点,第一个代码版本,先来个简单的,不带虚拟节点。

下面来看一下不带虚拟节点的一致性Hash算法的Java代码实现:

/** * 不带虚拟结点的一致性Hash算法 * @author 哓哓 * */public class ConsistentHashWithoutVN {​ /** * 待加入Hash环的服务器列表 */ private static String[] servers = { "192.168.0.0:111

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/455515.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《HTML5 Canvas游戏开发实战》——2.1 绘制基本图形

本节书摘来自华章计算机《HTML5 Canvas游戏开发实战》一书中的第2章&#xff0c;第2.1节,作者&#xff1a;张路斌著&#xff0c; 更多章节内容可以访问云栖社区“华章计算机”公众号查看。 2.1 绘制基本图形 所谓基本图形&#xff0c;就是指线、矩形、圆等最简单的图形&#x…

Npgsql使用入门(三)【批量导入数据】

Program.cs代码: class Program{static void Main(string[] args){var test new PgBulkCopyHelper<SingleBuilding>("bld_amap_gzmain");foreach (string pName in test.PropNames){Console.WriteLine("name: {0},\t\ttype: {1}", pName, test.Prop…

远程网络视频监视技术

目前要实现广域网视频监视&#xff0c;主要通过三种方式实现&#xff1a;1.硬盘录像机&#xff1b;2.网络视频服务器&#xff1b;3.网络摄像机。 硬盘录像机是一个以录像为主的设备&#xff0c;有的可以支持IE浏览。网络视频服务器一般前端不录像&#xff0c;直接将影像传输到…

python常用代码_Python常用算法学习(3)(原理+代码)——最全总结

1&#xff0c;什么是算法的时间和空间复杂度算法(Algorithm)是指用来操作数据&#xff0c;解决程序问题的一组方法&#xff0c;对于同一个问题&#xff0c;使用不同的算法&#xff0c;也许最终得到的结果是一样的&#xff0c;但是在过程中消耗的资源和时间却会有很大的区别。那…

数据监测驱动下的信息流广告优化

信息流广告是什么 “今日头条和百度必有一战”&#xff0c;相信不少的互联网人在过去几个月都听到过类似的断言。定位于信息分发平台的今日头条和主营搜索业务的百度会产生如此大的利益冲突&#xff0c;最核心的点其实就是信息流广告。 信息流广告指的是在用户使用互联网产品或…

在idea中使用git管理你的项目

起步 idea是十分智能的Java集成开发环境 而我们在用idea写项目的时候经常遇到版本控制的问题,而git工具如果你只会在终端中的git命令来进行控制,可能会使得效率低下 今天小编就教大家在idea中使用git来管理你的项目 首先创建一个项目 点击create new projects 这里选择默认…

偏好设置

转载于:https://www.cnblogs.com/xufengyuan/p/6959424.html

keyshot环境素材文件_快速学会keyshot基础渲染的步骤

KeyShot是基于CPU为三维数据进行渲染和动画操作的独立渲染器。意为“The Key to Amazing Shots”&#xff0c;是一个互动性的光线追踪与全域光渲染程序&#xff0c;无需复杂的设定即可产生相片般真实的 3D 渲染影像。KeyShot超强的渲染能力广泛的应用于工业产品、机械工程、CG行…

传统数据中心如何实现向云的平滑升级

1.引言 众所周知&#xff0c;云计算是近年来发展最快的互联网技术&#xff0c;被称为第四次IT革命。据权威机构预测&#xff0c;到2016年&#xff0c;2/3的IT应用服务将建立在云架构上 [1]。作为云计算核心的基础承载设施&#xff0c;数据中心在网络中所扮演的角色也愈加重要。…

上位机与基恩士plc以太网通讯_2020湛江AB罗克韦尔PLC主机回收二手或全新

2020湛江AB罗克韦尔PLC主机回收二手或全新专业回收基恩士光电传感器回收&#xff0c;基恩士安全光栅回收&#xff0c;基恩士对射开关回收&#xff0c;基恩士工控配件回收&#xff0c;基恩士视觉相机回收&#xff0c;发那科伺服驱动电机回收&#xff0c;发那科控制系统回收&…

生物信息学概论_大学专业详解系列83——生物信息学(理学学士)

生物信息学(理学学士)毕业生应具备的知识和能力(1)掌握扎实的数学、物理、化学基础理论和基本知识&#xff1b;(2)掌握生物学专业基础知识和信息处理的专门知识&#xff1b;(3)掌握普通生物学、细胞生物学、遗传学、分子生物学、生物数据库管理系统、生物信息学、基因组学、蛋白…

Butterknife全方位解析

概述 Butterknife是供职于Square公司的JakeWharton大神开发的开源库&#xff0c;使用这个库&#xff0c;在AS中搭配Android ButterKnife Zelezny插件&#xff0c;可以大大提高开发的效率&#xff0c;从此摆脱繁琐的findViewById(int id)&#xff0c;也不用自己手动bind(int id)…

论文笔记 Aggregated Residual Transformations for Deep Neural Networks

这篇文章构建了一个基本“Block”&#xff0c;并在此“Block”基础上引入了一个新的维度“cardinality”(字母“C”在图、表中表示这一维度)。深度网络的另外两个维度分别为depth&#xff08;层数&#xff09;、width&#xff08;width指一个层的channel的数目&#xff09;。 首…

matlab 归一化_机器学习中如何用Fscore进行特征选择(附Matlab代码)

作者&#xff1a;kervin编辑&#xff1a;阿吉 目前&#xff0c;机器学习在脑科学领域的应用可谓广泛而深入&#xff0c;不论你是做EEG/ERP研究&#xff0c;还是做MRI研究&#xff0c;都会看到机器学习的身影。机器学习最简单或者最常用的一个应用方向是分类&#xff0c;…

IOS安装CocoaPods完整流程

作为一个底层系统大菜鸟,又搞过几年ios来说,安装一个CocoaPods是一件蛋痛的事~ 说懂又懂,说不懂又不懂. 由于安装过程比較复杂,步骤较多,而网上教程又比較零散,并且有一些是扯蛋的,所以本篇文章主要从头到位依据自身安装经历记录每一条终端指令,至于里面的原理和一些概念性的东…

linux 修改时区_教你在Centos8中更改时区

对于许多与系统相关的任务和进程&#xff0c;使用正确的时区是必不可少的。例如&#xff0c;cron守护进程使用系统的时区执行cron作业&#xff0c;日志文件中的时间戳基于同一系统的时区。环 境CentOS 8检查现在的时区timedatectl是一个命令行实用程序&#xff0c;允许您查看和…

vb6在后台将窗体保存到图片_如何将寺库网多个商品图片一键分类保存到一个目录...

寺库网是全球最大的奢侈品网上在线购物平台&#xff0c;那么我们怎样可以从寺库网上一键批量采集到多个宝贝商品图片&#xff0c;并分类保存到电脑呢&#xff1f;今天小编给大家带来一款专业电商图片链接采集软件【载图助手】&#xff0c;它支持平台高达141个&#xff0c;均可支…

浮动与定位

2019独角兽企业重金招聘Python工程师标准>>> 一.浮动:float:一个元素浮动时,其他内容会"环绕"该元素. 浮动元素的外边距不会合并浮动的元素不能超出其包含快的内边界浮动元素彼此会避免重叠浮动元素的顶端不能比之前所有浮动元素或块级元素的顶端更高如果…

驱动级的自动按键_Aqara全自动智能推拉锁D100,体验全自动开门的便捷

大家好&#xff0c;我是梦想是个猪&#xff0c;今天为大家带来的是一篇智能门锁的使用体验。前言家里的这张门陆陆续续的换了好几把智能门锁了&#xff0c;也体验了好几种不同的开锁方式。最开始开发商给安装的是一把指纹和把手分离的那种款式&#xff0c;开锁的时候需要先输入…

深度学习综述

摘要&#xff1a; 深度学习可以完成需要高度抽象特征的人工智能任务&#xff0c;如语音识别、图像识别和检索、自然语言理解等。深层模型是包含多个隐藏层的人工神经网络&#xff0c;多层非线性结构使其具备强大的特征表达能力和对复杂任务建模能力。训练深层模型是长期以来的难…