一致性哈希算法

背景

这个分享来自前阵子的我自己去面试的时候一道面试题。
和面试官大致对线如下:
面试官:用过mysql吧?
我:用过
面试官:数据量大的时候单从mysql层面怎么解决查询效率问题?
我:分库分表
面试官:那能具体说说主键是怎么分布的吗?
我:主键采用一致性哈希算法取模存到对应的库中且key能平均分布
面试官:那一致性哈希算法的原理是啥?它是如何保证key能平均分布的?
我:……
为了知其然也要知其所以然,查阅了一些资料后记录一下

场景

先试想一个场景:
假如有3台服务器,有一个文件要存入其中一台服务器。key.hashCode%3得到一个服务器编号,然后存入,取也根据hashCode%3取没问题。

取模操作


假如之前文件A存入了1号服务器,现在服务器升级变成了4台,或者3台其中一台挂了,在被除数(hashCode)不变,除数(3台)发生改变的时候,势必会在取文件时会造成短时间内取不到所有文件的情况。

在这里插入图片描述

一致性哈希

一致性哈希确实能解决上面的问题。它其实也是采用了取模的方式,只不过上面取模的除数是服务器个数,一致性哈希取模的除数是2^32。
首先,我们把二的三十二次方想象成一个圆,就像钟表一样,钟表的圆可以理解成由60个点组成的圆,而此处我们把这个圆想象成由2^32个点组成的圆,示意图如下:

在这里插入图片描述


我们把这个由2^32个点组成的圆环称为hash环。
还按上面的例子,假如3台服务器的话,这里hash的是每台服务器的ip地址,然后** % 2^32。**
公式为:

hash(服务器ip)% 2^32

通过上述公式算出的结果一定是一个0到232-1之间的一个整数,我们就用算出的这个整数,代表服务器A,既然这个整数肯定处于0到232-1之间,那么,上图中的hash环上必定有一个点与这个整数对应,而我们刚才已经说明,使用这个整数代表服务器1,那么,这个服务器就可以映射到这个环上,如下图所示:

在这里插入图片描述



同理,我们把2和3服务器也映射进去,大致如下图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/img_convert/0f06fa7589344a960447f65a583cb762.png#clientId=ue0c3d7fb-873f-4&from=paste&height=559&id=u8833c92f&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1118&originWidth=1108&originalType=binary&ratio=1&size=89492&status=done&style=none&taskId=uc4a15338-1524-41a4-8547-188e0fe509b&width=554#pic_center)


好了,精彩的部分来了。
在存/取文件的时候,计算文件的hash取模的方式也和之前发生了点变化。
现在也变成了

hash(文件名) % 2^32

文件取完模之后的值和服务器一样,一定也是在0到2^32-1之间。假如计算后的值对应在圆环中位置如下图:
![image.png](https://img-blog.csdnimg.cn/img_convert/99bb600c5cac431471b51c418b958419.png#clientId=ue0c3d7fb-873f-4&from=paste&height=533&id=uf7a4de48&margin=[object Object]&name=image.png&originHeight=1066&originWidth=1050&originalType=binary&ratio=1&size=87534&status=done&style=none&taskId=uacebd282-31ae-4128-881d-4c922a0b26b&width=525)
那么此时文件A就会放到1号服务器上。因为从文件A对应的位置,顺时针往前计算离1号服务器最近,一致性哈希算法就是通过这种方法,判断一个对象应该被存到哪台服务器上的。所以在服务器不变的情况下,也是可以正常获取到数据的。
不过这么看好像也还没解决开头的问题?如果服务器挂了怎么办?下面我们来模拟下服务器挂掉的情况。

在这里插入图片描述


假设现在2号服务器挂掉了,根据一致性哈希原理,只需要把文件B和文件D移动到3号服务器即可。对于文件C和文件A,即使是2号挂掉了也不会影响这两个文件的读取。
假设现在新增了一台服务器,对于下图中这个实际情况来说,也就只用把B和D移动到4号服务器即可。对于A和C依然没有读取影响。
![image.png](https://img-blog.csdnimg.cn/img_convert/11d6b2a978476cf0ca0054283109cce8.png#clientId=ue0c3d7fb-873f-4&from=paste&height=580&id=u61dc0669&margin=[object Object]&name=image.png&originHeight=1160&originWidth=1080&originalType=binary&ratio=1&size=101797&status=done&style=none&taskId=uba209b74-d171-4852-9fc4-b90f0fe9fa2&width=540)
你以为这就结束了吗?其实这里还有一个问题。


hash环偏斜

上图中的服务器分布是相对理想的情况,然而实际情况的服务器分布很可能是这样的:

![image.png](https://img-blog.csdnimg.cn/img_convert/3e69f68f9544ad1d5eec81851fc67e23.png#clientId=ue0c3d7fb-873f-4&from=paste&height=578&id=u9620c436&margin=[object Object]&name=image.png&originHeight=1156&originWidth=1102&originalType=binary&ratio=1&size=103535&status=done&style=none&taskId=ud720afe4-4e9b-46ae-be20-a79e76d5001&width=551)
如果出现这种分布,那么ABCD4个文件都会存到1号服务器中。1号服务器的压力会很大,数据分布不均匀本质上甚至和单机服务没什么区别。这种现象我们称之为hash环倾斜。

虚拟节点

那么如何解决hash换偏斜问题呢?这里引入一个概念:虚拟节点。
说白了,这东西就是图中1234号服务器的影分身,虚拟出来的节点位置等于本体,其实还是4台服务器,只不过加了和真实服务器的映射关系。如图:
![image.png](https://img-blog.csdnimg.cn/img_convert/586676a22c3342daa1d3f00258a1b0c2.png#clientId=ue0c3d7fb-873f-4&from=paste&height=560&id=ucfb9eeae&margin=[object Object]&name=image.png&originHeight=1120&originWidth=1120&originalType=binary&ratio=1&size=117452&status=done&style=none&taskId=u9e8065b0-7921-4f7c-965c-ad00756a4ae&width=560)
图中虚线的1234分别对应真实服务器1234。对于图中这个案例来说:
文件A–1号服务器,因为顺时针最近的就是1号实体服务器
文件B–2号服务器,顺时针2号服务器的虚拟节点,故存入2号服务器
文件C–3号服务器,顺时针3号服务器的虚拟节点,故存入3号服务器
文件D–4号服务器,顺时针4号服务器的虚拟节点,故存入4号服务器
虚拟节点越多,数据则分布越均匀。
至于为什么是232,是因为ipv4的总个数就是232个,这样就能保证所有的ip地址来取余不会重复。

以上就是关于一致性哈希的一些讨论,如有不对,欢迎赐教。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值