大厂面试必备分布式存储算法--redis集群(精讲必会大厂敲门砖)

序言:

亿级数据缓存,设计储存方式:单机单台是不可能的,必须使用分布式,使用redis该怎么实践呢?

一、哈希取余算法

先来看一张图:

2bedb2285dbf45c385b4188beb8d9715.png

假如有1亿条数据要储存,也就是说有1亿个k-v,单机存储肯定是不行的,必然是分布式多机存储

假设有三台机器构成的集群,用户的每次访问都会通过一个公式hash(key)%N计算出哈希值,为什么使用key来哈希,因为每个v的key都是不重复的!计算出哈希值再决定映射到具体的哪个节点上

优点:当然是简单易部署,直接使用哈希算法让某些访问固定的映射到某台服务器上,这样每台服务器就起到了负载均衡和分而治之。

缺点:很明显我们的那个N(机器的数量)是固定的,也就是已经规划好了结点,当我们进行扩容的时候就比较麻烦每次改变服务器的数目都会导致节点的数目的变动,那么映射关系就会变化,必须进行重新计算,那么此时如果计算(取余运算)结果就会和之前的大相径庭,那么获取的服务器也变得不可控。另外如果出现了服务器宕机,由于数目的变化,那么之前的计算数据就会全部打乱。

二、一致性哈希算法

1.概念:一致性哈希算法时有麻省理工学院于1997年提出的目的就是为了解决分布式缓存数据的变动的映射问题。主要动机是在动态添加或删除哈希表节点时,能够“尽可能小”地改变已存在的键值对映射关系。这种特性使得一致性哈希在分布式缓存系统、负载均衡等领域得到了广泛的应用。

2.思想:一致性哈希算法的核心思想是将所有的哈希值组织成一个虚拟的圆环,一个首尾相接的圆环,范围从0到2^32-1。同时,将机器节点也映射到这个圆环上。对于数据的存储和查找,首先计算键的哈希值,然后顺时针找到第一个大于或等于该哈希值的机器节点,将数据存储在该节点上。如果后续有机器加入或退出集群,只需要重新定位受影响的键即可,而不需要重新定位整个哈希环上的所有键。注意:这里也是取余但是我们发现哈希取余算法时对机器的台数进行取余,而一致性哈希算法时对2^32取余是一个固定的值,那么某哈希函数对其取余之后范围是0~2^32-1这就是形成了一个闭环,按照顺时针组织:见图:

23c4aa325cbc4887af2949466aee61aa.png

再大的饼也大不过烙它的锅!哈希之后点必然落在这个虚拟的环上!

3.节点映射:把集群中的服务器按照各个服务器的IP或者主机名进行哈希,那么每个服务器就会有一个结点再虚拟的环上并且位置是确定的;比如:有四台服务器经过IP进行哈希之后落点再NodeA,NodeB,NodeC,NodeD四个点上:

77b83c0fd7dc4394bd6f990191a199ed.png

4.落键规则:当我们需要存储一个k-v键值对时,首先根据key值来计算出哈希值,hash(key)使用的哈希函数是计算服务器落点的函数,那么计算出的hash(key)必定能够落在虚拟环上,按照落点的位置顺势针转圈,遇到第一台服务器就是其对应到的服务器,把键值对存储在该结点映射服务器上,比如下图中:ObjectA、ObjectB、ObjectC、ObjectD四个数据在经过哈希之后都有了落点,那么开始顺时针“行走”结果:ObjectA-->NodeA;ObjectB-->NodeB;ObjectC-->NodeC;ObjectD-->NodeD

29e7f2aea7764203a3b8945ccf43279b.png

以上就是一致性哈希算法的思路和映射规则!那么它有什么优点和缺点呢?

优点:解决了哈希取余算法的容错性和扩展性,假如NodeC宕机,可以看到此时对象A,B,D并不会受到影响,只有C对象被重新定位了,顺时针行走到达NodeD,我们就发现受影响的取余仅仅是此服务器到其前面的第一台服务器之间的距离(也就是逆时针方向行走遇到的第一台服务器之间的距离)而且这些数据会被转储到下一个服务器NodeD上;

71c59c08e7e0482285241cd841a0ab0f.png

扩展性:当前我们的服务器数量增加,为NodeX再A和B结点之间,受到影响的数据也只有A到X之间的区域,只需要重新把A到X区域之间的数据重新导向到X结点即可,不会导致大面积的洗牌。

2158f59491ba487ea517d9c85c7f4a76.png

缺点:数据倾斜问题:当节点太少的时候容易造成数据倾斜,被缓存的对象那部分搭载一台服务器上,如下图(一般数据量较少时不建议使用一致性哈希算法,大量的数据缓存比较适合):

1d19472c78f74541b002ef75b4ba0ae1.png

三、虚拟一致性哈希分区(较简单不做过多阐述)

相当于就是再虚拟一致性算法基础上衍生出来的,也就是为了增加分布均匀度!

11d16be88a3b4d90aee0f5f1df24abd5.png

279881933906401d85d183aeab052768.png

四、哈希槽分区(重点,大厂必用,典型的加一层)

1.概念:哈希槽分区是Redis集群中使用的一种数据分区策略,主要用于解决一致性哈希算法可能存在的数据倾斜问题,实现数据的均匀分布。具体来说,哈希槽实质是一个数组,数组的范围从0到2^14-1是一个数组(共16384个槽),形成了一个hash slot空间。为什么是16384个槽?这其实是redis之父Antirez及其团队精心设计的;详情见:http://antirez.com/news/75

2.思想:在Redis集群中,哈希槽(Hash Slot)是实现数据分布和高可用性的关键设计。集群会将整个键空间划分为16384个哈希槽,并通过CRC16算法将每个键映射到特定的哈希槽中。每个节点负责一部分哈希槽,从而实现数据的分布。

理想情况下,哈希槽的分配是均匀的,每个节点处理的数据量大致相同,从而避免了数据倾斜的问题。然而,在实际应用中,由于多种因素(如节点数量的变化、哈希函数的特性、数据的键值分布等)可能导致哈希槽的分配不均衡,进而引发数据倾斜。

例如,当节点加入或离开集群时,Redis会自动重新分配哈希槽。但这个过程可能并不总是完美的,有时会导致某些节点负责的哈希槽数量明显多于其他节点,从而造成数据倾斜。另外,如果数据的键值中包含有序数字或有特定模式,CRC16算法计算出的哈希值可能会集中在某个范围内,进一步加剧数据分布的不均衡。(但已经在很大程度上使其均匀分布了数据均衡了)

2d7f7bbd1a9542ac9eb6a47174c985ad.png

3.为了检测和解决Redis集群中的数据倾斜问题,可以采取以下措施:

(1)、监控节点的哈希槽分布情况:使用Redis提供的命令(如CLUSTER SLOTS)来查看每个节点负责的哈希槽范围,从而判断是否存在数据倾斜。
(2)、平衡哈希槽分配:如果发现数据倾斜,可以手动调整哈希槽的分配,使其更加均衡。这通常涉及将一部分哈希槽从一个节点迁移到另一个节点。
(3)、优化数据和键的设计:避免使用具有特定模式或有序数字的键,以减少哈希函数导致的分布不均衡
请注意,尽管哈希槽机制有助于解决数据倾斜问题,但在某些复杂场景下可能仍需要其他策略和工具来进一步优化数据分布和集群性能。同时,对于大规模或高要求的生产环境,建议定期进行性能监控和调优,以确保集群的稳定性和高效性。

需要注意的是,解决数据倾斜问题不仅仅是技术问题,还需要考虑到实际的应用场景和业务需求。因此,在处理数据倾斜问题时,建议综合考虑多种因素,并采取相应的措施来解决。


看到这会发现一个问题既然再改变结点之后会进行自动的重新分配,那么为什么还会出现数据倾斜呢?

其实在极端的情况下还是存在数据倾斜的风险的:比如:

1.键的分布不均匀:Redis集群使用哈希函数将键映射到哈希槽上。如果键的分布本身就不均匀(例如,某些键具有相似的哈希值或遵循某种模式),那么这些键可能会被映射到相同或相近的哈希槽中,从而导致某些哈希槽承载更多的数据1。

2.数据迁移的限制:在重新分配哈希槽的过程中,Redis会尝试将数据从一个节点迁移到另一个节点。但是,这个过程可能受到网络带宽、磁盘I/O性能或集群规模的限制,导致数据迁移不完全或速度较慢,从而无法实现完全均匀的数据分布1。

3.集群扩展的不均衡:当需要扩展Redis集群时,新的节点可能被添加到集群中。如果新的节点被添加到了已有节点数据较多的部分,或者添加的节点数量与现有节点数量不匹配,就可能导致存储不均匀1。

4.哈希槽分配算法:虽然Redis集群使用固定的哈希槽数量和分配算法,但在某些情况下,这种算法可能无法完全适应节点数量或数据分布的变化,从而导致分布不均。


解决方案:(看了和多种解决方案,最后总结了两种解决方案,如果还有更好的解决方案欢迎在评论区留言,方便推广给大家)

1.优化键的分布:尽量使用随机的、分布均匀的键,避免使用具有相似哈希值或遵循特定模式的键。
2.监控和调整:定期监控集群中哈希槽的分布情况,如果发现不均匀,可以手动调整或触发重新平衡操作。


一共有16384个哈希槽,编号从0~2^14-1,把这些槽分配给所有主节点,分配策略任意的,可以指定哪些槽给哪个主节点,对key值进行哈希,求出哈希值之后,对16384求余,余数肯定落点在对应的槽里,slot=CRC16(key)%16384.以槽为单位移动数据,因为槽的数据是固定的,容易处理。

6e8b119fabcf4ef8a8f21aa0bc4ade4c.png

通过公式slot=CRC16(key)%16384计算出一个k-v对应的槽位在0-16383之间再映射到某个结点。如上图中有三台机器可供分配哈希槽,计算一个key的哈希再求余就会对应一个结点。

有Java代码如下举例:

b1f974d4caa34bff89322b6a3533fae8.png

这么就会对应相应的哈希槽继而是结点!可以很明显的看出这四个key对应的节点是A、B对应Node2,C对应Node3,hello对应Node1


后续还会有具体的实战案例!欢迎关注!及时接收!有任何问题或者建议欢迎在评论区留言!

7be1863a865e47f6a5dd79ca5e45a349.png

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值