33、一致性哈希算法分区
- 一、背景
- 二、介绍
- 三、步骤
- 1、算法构建一致性哈希环
- 2、Redis服务器IP节点映射
- 3、key落到服务器的落键规则
- 四、优点
- 1、一致性哈希算法的容错性
- 2、一致性哈希算法的扩展性
- 五、缺点
- 1、一致性哈希算法的数据倾斜问题
- 2、拓展
- 六、总结
一、背景
一致性哈希算法 出现的原因:
分布式缓存数据变动和映射的问题。例如 哈希取余分区 某个机器宕机了,分母数量改变了,自然取余数不OK了。
提出 一致性哈希算法 的解决方案,目的是当服务器个数发生变动时,尽量减少影响客户端与服务器的映射关系。
二、介绍
一致性哈希算法 本质上也是一种取模算法。不过,不同于 哈希取余分区 按服务器数量取模。一致性哈希算法是对固定值 2^32
取模。
IPv4的地址是 4组8位2进制数
组成,所以用2^32
可以保证每个IP地址会有唯一的映射。例如:0.0.0.0 ~ 255.255.255.255,为所有 ip
段。
三、步骤
1、算法构建一致性哈希环
一致性哈希算法:
(1) 根据 Hash函数 并按照算法产生 Hash值。
(2) 产生的 Hash值 会构成一个全量集,这个集合可以成为一个 hash空间 [0,2^32-1] 。这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连(0 = 2^32),这样让它逻辑上形成了一个环形空间,简称哈希环。
(3)哈希环如下图: 整个空间按 顺时针 方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、……直到2^32-1。
2、Redis服务器IP节点映射
将集群中各个 IP节点(Master) 映射到环上的某一个位置。
此时计算公式就从 hash(key) % n
变成了 hash(服务器ip)% 2^32
,使用 服务器IP 地址进行 哈希计算 ,用哈希后的结果对 2^32取模 。结果 一定 是一个 [0,2^32-1]
之间的整数,而这个整数映射在 Hash环 上的位置代表了一个服务器,依次将NodeA、NodeB、NodeC、NodeD四个缓存服务器映射到hash环上。
3、key落到服务器的落键规则
存储 kv键值对
时:
(1)首先计算 key
的 hash
值,hash(key)
。
(2)将这个 key
使用 相同 的 Hash函数 计算出 Hash值 并确定此数据在环上的位置。
(3)从此位置沿环 顺时针“行走” ,第一台 遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。
(4)例如:key 1、key 2、key 3、key 4四个数据对象,经过Hash计算后,在环空间上的位置如下:根据一致性哈希算法,key 1会被定为到Node A上,key 2被定为到Node B上,key 3被定为到Node C上,key 4被定为到Node D上。
四、优点
1、一致性哈希算法的容错性
假设 Node C 宕机,可以看到此时对象A、B、D不会受到影响。
一般的,在一致性哈希算法中,如果一台服务器不可用,则 受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据 ,其它不会受到影响。
简单说,就是C挂了,受到影响的只是B、C之间的数据且这些数据会转移到D进行存储。
2、一致性哈希算法的扩展性
当数据量增加,需要新增加一台节点 Node X,Node X 的位置在A和B之间,那收到影响的也就是A到X之间的数据,重新把A到X的数据录入到X上即可,不会导致Hash取模全部数据重新洗牌。
五、缺点
1、一致性哈希算法的数据倾斜问题
上文为了便于理解原理,图中的Node节点都很理想化的均匀分布,但理想,实际的场景往往差别很大,就比如办了个健身年卡,只去过健身房两次,还只是洗了个澡。
一致性哈希算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题。
例如系统中只有两台服务器,被缓存的数据对象大部分缓存在Node A服务器上,导致其他节点资源浪费,系统压力大部分集中在Node A节点上,这样的集群是非常不健康的。
2、拓展
为了解决一致性哈希算法的数据倾斜问题,提出了一个虚拟节点的机制。即对每个服务器节点计算出多个Hash值,它们都会映射到Hash环上,映射到这些虚拟节点的对象key,最终会缓存在真实的节点上。
虚拟节点的Hash计算通常可以采用,对应节点的 IP地址+数字编号 后缀。例如:hash(192.168.250.128#1) 。
举个例子,Node A节点IP为192.168.250.128,正常计算Node A 的Hash值。
- hash(192.168.250.128)% 2^32
假设给Node A设置三个虚拟节点,Node A#1、Node A#2、Node A#3,分别对它们进行Hash后取模。
- hash(192.168.250.128#1)% 2^32
- hash(192.168.250.128#2)% 2^32
- hash(192.168.250.128#3)% 2^32
给Node B设置三个虚拟节点,Node B#1、Node B#2,分别对它们进行Hash后取模。
- hash(192.168.250.129#1)% 2^32
- hash(192.168.250.129#2)% 2^32
给Node C设置三个虚拟节点,Node C#1,对它进行Hash后取模。
- hash(192.168.250.130#1)% 2^32
如下图加入虚拟节点后,原有节点在Hash环上分布的就相对均匀了,其余节点压力得到了分摊。
但需要注意一点,分配的虚拟节点个数越多,映射在hash环上才会越趋于均匀,节点太少的话很难看出效果。
引入虚拟节点的同时,也出现了新的问题,要做虚拟节点和真实节点间的映射,对象key->虚拟节点->实际节点之间的转换。
如下图所示:
六、总结
(1)一致性哈希算法 在分布式系统中应该是实现负载均衡的首选算法。
(2)目的: 在节点数目发生改变时尽可能少的迁移数据.
(3)流程: 将所有的存储节点排列在 首尾相接的Hash环 上,每个 key
在计算 Hash值 后会顺时针找到临近的存储节点存放。而当有节点新增或减少仅影响该节点在Hash环上顺时针相邻的后续节点。
(4)优点: 新增或减少节点只影响哈希环中顺时针方向的相邻的节点,对其他节点无影响。
(5)缺点: 数据的分布和节点的位置有关,因为这些节点不是均匀的分布在哈希环上的,所以数据在进行存储时达不到均匀分布的效果。
到这里 一致性哈希算法分区 就结束了!!!🎉🎉🎉
欢迎小伙伴们学习和指正!!!😊😊😊
祝大家学习和工作一切顺利!!!😎😎😎