一致性Hash算法的原理

一. 背景

随着业务的扩展,流量的剧增,单体项目逐渐划分为分布式系统。对于经常使用的数据,我们可以使用Redis作为缓存机制,减少数据层的压力。因此,重构后的系统架构如下图所示:
简单架构
在这里插入图片描述
优化最简单的策略就是,把常用的数据保存到Redis中,为了实现高可用使用了3台Redis(没有设置集群,集群至少要6台)。每次Redis请求会随机发送到其中一台,但是这种策略会引发如下两个问题:

同一份数据可能在多个Redis数据库,造成数据冗余
某一份数据在其中一台Redis数据库已存在,但是再次访问Redis数据库,并没有命中数据已存在的库。无法保证对相同的key的所有访问都发送到相同的Redis中
要解决上述的问题,我们需要稍稍改变一些key存入Redis的规则:使用hash算法
例如,有三台Redis,对于每次的访问都可以通过计算hash来求得hash值。
如公式 h=hash(key)%3,我们把Redis编号设置成0,1,2来保存对应hash计算出来的值,h的值等于Redis对应的编号。
但是hash算法也会面临容错性和扩展性的问题。容错性是指当系统中的某个服务出现问题时,不能影响其他系统。扩展性是指当加入新的服务器后,整个系统能正确高效运行。

现假设有一台Redis服务器宕机了,那么为了填补空缺,要将宕机的服务器从编号列表中移除,后面的服务器按顺序前移一位并将其编号值减一,此时每个key就要按h = Hash(key) % 2重新计算。

同样,如果新增一台服务器,规则也同样需要重新计算,h = Hash(key) % 4。因此,系统中如果有服务器更变,会直接影响到Hash值,大量的key会重定向到其他服务器中,造成缓存命中率降低,而这种情况在分布式系统中是十分糟糕的。

一个设计良好的分布式哈希方案应该具有良好的单调性,即服务节点的变更不会造成大量的哈希重定位。一致性哈希算法由此而生

二.原理

1.首先求出memcached服务器(节点)的哈希值,并将其配置到0~232的圆(continuum)上。
2.然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。
3.然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器,就会保存到第一台memcached服务器上。
在这里插入图片描述
从上图的状态中添加一台memcached服务器。余数分布式算法由于保存键的服务器会发生巨大变化而影响缓存的命中率,但Consistent Hashing中,只有在园(continuum)上增加服务器的地点逆时针方向的第一台服务器上的键会受到影响,如下图所示:
在这里插入图片描述
节点分布不均的解决
一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。例如系统中只有两台服务器,其环分布如下,
在这里插入图片描述
此时必然造成大量数据集中到Node A上,而只有极少量会定位到Node B上。为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。具体做法可以在服务器ip或主机名的后面增加编号来实现。例如上面的情况,可以为每台服务器计算三个虚拟节点,于是可以分别计算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值,于是形成六个虚拟节点:
在这里插入图片描述
同时数据定位算法不变,只是多了一步虚拟节点到实际节点的映射,例如定位到“Node A#1”、“Node A#2”、“Node A#3”三个虚拟节点的数据均定位到Node A上。这样就解决了服务节点少时数据倾斜的问题。在实际应用中,通常将虚拟节点数设置为32甚至更大,因此即使很少的服务节点也能做到相对均匀的数据分布。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值