Cluster集群可以基于一致性哈希算法么?
作者:程序员马丁
在线博客:https://open8gu.com
大话面试,技术同学面试必备的八股文小册,以精彩回答应对深度问题,助力你在面试中拿个offer。
回答话术
首先,由于数据要分片存储在不同的服务器节点上,因此当用户发起请求时,我们会需要一个哈希算法保证对某个 Key 的请求总是路由到指定的服务器节点。传统的哈希算法基于长度(也就是节点数量)进行取模,因此当扩容和缩容时会需要对大量的数据进行迁移。而一致性哈希算法则用于解决这个问题。
在一致性哈希中,规定了一个固定大小的哈希环,环上均匀分布有 2^32 个节点,服务器节点也分布在环上。当用户发起请求时,将会根据 Key 的哈希值计算出落点,若 Key 的落点没有对应的服务器节点,则顺时针寻找最近的服务器节点。当扩容时,仅需要对新节点与上一节点之间的数据进行迁移,而缩容亦同理。
一致性哈希的优点在于避免了传统哈希算法中扩容和缩容时的大规模数据迁移,但是它也有缺点,那就是当节点在环上分布不均匀就可能导致数据倾斜。因此,当节点掉线或缩容时,可能因为将全部数据压到下一节点而导致服务雪崩。为了解决这个问题,我们需要允许一个节点在环上映射出多个虚拟节点,这样就能尽可能的使请求均匀的打到不同的服务器上。
Redis 集群采用的哈希槽方案同样基于固定数量(2^14)的哈希槽实现,不过相对于一致性哈希,每个节点拥有的哈希槽是可以直接分配的:
- 我们可以直接根据服务器的性能而为它们分配不同数量的哈希槽位,一致性哈希虽然也可以通过改变某个服务器对应虚拟节点的数量做到类似的效果,不过显然没有这么精准。
- 当扩容和缩容的时候,我们可以手动指定将哪些槽位转移到哪些节点,而一致性哈希则做不到类似的效果。
总的来说,哈希槽在使用上比一致性哈希更加灵活,并且实现上也更加简单。
问题详解
1. 为什么需要哈希算法?
在 Redis 集群中,每个分片中的节点存储的数据都是不一样的。因此当客户端进行访问的时候,就需要有一个哈希算法,能保证总是将同一个 Key 路由到一个相同的节点上。
要实现这样的效果,最简单方法就是直接根据节点总数取模,比如我们有三个节点,那么就需要对所有的 Key 哈希值基于三取模( hash(key) % 3
),最终得到的模数即为要访问的节点下标。
不过这个方案有一个致命的缺点,由于节点数量直接影响计算结果,因此当扩容或者缩容的时候,由于 Key 的哈希结果会发生变化,因此可能会引起大规模的数据迁移。
2. 什么是一致性哈希?
2.1. 概述
一致性哈希算法与传统哈希算法一样,也基于长度取模,但是它的长度是一个固定值 2^32。
它假设 2^32 个节点均匀分布在一个哈希环中,然后: