前言
接上篇 图解 Redis 哨兵模式,整个 Redis 的高可用方案还剩下Cluster
集群模式(后面统称为Cluster
)没有弄。Cluster
相关的话计划是用两篇来弄,第一篇就是今天这个关于Cluster
模式下的hash slot
算法。基本上把这个算法的原理弄清楚整个Cluster
就基本差不多了。关于这个hash slot
会通过最基本的hash
算法、一致性hash
算法到hash slot
算法基本思路通过画图的方式让好哥哥更好的理解。觉得图画的不错的好哥哥们点个赞加个关注吧(讲道理图还是很难画的,有的时候基本一幅图就得一上午这种)。
概述
不知道好哥哥们有没有看过或者自己动手实践过数据库的分库分表
,相信好哥哥们都有对数据库的分库分表有过一些理解(没有的话先百度看个大概),在做分库或者分表时需要考虑的一个问题就是数据的分布采用什么方式。常见的数据分布方式有哈希
(取余hash
、一致性hash
)、按数据范围
、 按数据量
。
当然,在这里我们就不详细的去对比各种数据分布方式的应用场景以及其优劣势了。在Cluster
中数据分布式方式选择的是哈希分区规则
。而哈希分区
也有很多种实现方式,这里话主要图解节点取余hash
、一致性hash
、虚拟槽hash
。
取余 hash
取余hash
会使用特定的数据,比如说用户Id
、手机号等,再根据节点的数量N
通过公式:hash(key) % N
计算出哈希值。如下图:
比如我们有三台 Redis 的主服务器,我们要存储用户id
为10
的数据。这时我们的公式为:hash(10) % 3 = 1
(hash(10) = 10
),我们就可以定位到将用户用户id
为10
的数据存入到master1
的服务器节点中。当我们获取数据时一样通过公式能定位到master1
主节点,这们就省去了遍历所有服务器的时间,从而大大提升了性能。
优劣势
优势
这种方式的突出优点是简单性
,常用于数据库的分库分表规则,一般采用预分区的方式。提前根据数据量规划好分区数,比如划分为512
或1024
张表,保证可支撑未来一段时间的数据量,再根据负载情况将表迁移到其他数据库中。扩容时通常采用翻倍扩容,避免数据映射全部被打乱导致全量迁移的情况。
劣势
这种方式的劣势也是很明显的,首先如上图,当某一个主节点出现网络异常或者宕机产生不可达现象时,会出现整个集群环境下可用服务器基数的变化(从三台变成两台)。从而导致整个集群不可用,因为涉及到的计算公式已经变化,造成数据失效、混乱等现象。
另一方面的话在整个集群环境的横向扩展(添加主节点)上也是很不友好的,需要对旧数据重新做数据与节点的关系映射。
一致性 hash
一致性hash
算法就是为了解决上面取余hash
的问题,首先失效的最主要原因是取余的基数是根据集群中的节点数动态变化的!一致性hash
算法把取余的基数固定为一个常数 232,这样可以做到以不变应万变。从而把取余范围控制在[0,232-1]的区间内,并把这个区间按照顺时针的方向均匀分布在一个圆环上,称之为hash环
(如上图)。
其次,由于一致性hash
算法把取余的基数固定为一个常数 232,从而也不存在横向扩容相关的问题。
如上图,当我们需要查询数据时,计算到的hash
值为10
(上图N1节点
顺时针第一个键)。这时我们的寻址规则就是根据圆环顺时针找到第一个大于等于该哈希值的数据节点(上图找到的是N2
节点)
优劣势
优势
这个的话上面基本上讲了,第一个就是解决数据失效的问题,其次就是不需要考虑横向扩容问题。有很好的容错性和可扩展性。
劣势
好哥哥们是不是觉得这个方案已经很完美了?当然不是的,假如说上图中的N2
节点宕机了,是不是就会出现通过hash
函数后落在N1
顺时针到N3
区间的数据都会使用N3
这个节点来提供服务。从而造成数据分布不均匀(数据倾斜)。
也就是说当使用少量节点时,节点变化将大范围影响哈希环中数据映射,因此这种方式不适合少量数据节点的分布式方案。在增减节点时需要增加一倍或减去一半节点才能保证数据和负载的均衡。
一致性 hash + 虚拟节点
这个的话就很好理解了,一致性hash
出现数据和负载的不均衡主要的问题是什么。那就是节点少,所以为了解决这个问题,你不是节点少吗,给我加,但是我没有那么多服务器呀咋整。诶,我给你整个虚拟的节点出来不久行了吗,服务器还是那几台,是不是就解决这个问题了。于是乎如上图会出现一些实际节点的虚拟节点。
刚刚不是说N2
节点宕机了吗,这时得到hash
值后通过顺时针方向就能找到一个N3
的虚拟节点,从而使用N3
这台服务器来提供服务。
优劣势
优势的话上面已经说了,主要的话就是解决一致性hash
数据倾斜和少量节点的问题。劣势的话就别鸡蛋里面挑骨头了,这已经很完美了好吗(主要是我不知道,有知道的好哥哥评论区告诉我)。
虚拟槽 hash
这个的话上面有提到过出发点的问题,比较细的好哥哥应该发现了(没发现的话就比较粗了),上面不管是取余hash
、一致性hash
还是一致性hash
加上虚拟节点都是从服务器的角度来寻址(通过hash
算法确定使用哪台服务器)。
而虚拟槽是个什么概念呢?虚拟槽
巧妙地使用了哈希空间,使用分散度良好的hash
函数把所有数据映射到一个固定范围的整数集合中,整数定义为槽(slot
)。这个范围一般远远大于节点数,比如Cluster
槽范围是0~16383
。槽是集群内数据管理和迁移的基本单位。采用大范围槽的主要目的是为了方便数据拆分和集群扩展。每个节点会负责一定数量的槽。
比如说,我们有下图的Master1
、Master2
、Master3
三台服务器,每台服务器中都包含16383 % 3 = 5461
槽(Master1
:0-5461
,Master2
:5462-10922
,Master3
:10922-16383
)。当我们需要获取hash
为100
的键时,这个时候就会落到Master1
这台服务器上面。所以虚拟槽的这种方式是以数据()为角度获取服务器。
优劣势
优势
- 解耦数据和节点之间的关系,简化了节点扩容和收缩难度(迁移槽就行了)。
- 节点自身维护槽的映射关系,不需要客户端或者代理服务维护槽分区元数据。
- 支持节点、槽、键之间的映射查询,用于数据路由、在线伸缩等场景。
- 某种意义上不存在数据倾斜的问题。
劣势
- 在某些场景下需要对业务做特殊处理,比如说需要按顺序查看数据时,需要将这一份数据落到同一台服务上面。
- 这种模式下不能支持批量操作,因为有可能批量数据可能存在多台服务其上面。
总结
这一篇的话主要是对取余hash
、一致性hash
和 cluster
寻址算法虚拟槽hash
理解。讲道理,这个也是会在面试的时候经常会问的,只要问道了 Redis 的高可用方案这个就是必须会问的。当然咯,理解这个对于整个 Redis cluster
集群模式还是很有帮助的。感觉有收获的好哥哥点个赞加个关注吧!
本期就到这啦,有不对的地方欢迎好哥哥们评论区留言,另外求关注、求点赞