Redis Cluster 为什么选哈希槽不选一致性哈希?

4,073 阅读6分钟

「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」。

Redis相信大家都很熟悉,它是我们常用的分布式缓存中间件之一。那么大家对于Redis Cluster集群是否熟悉呢?在Redis集群中并没有使用一致性hash, 而是引入了 哈希槽的概念,为什么选哈希槽不选一致性哈希。

1 Redis Cluster简单介绍

Redis Cluster就是Redis集群,为什么会有Redis Cluster呢?

首先说Redis就是远程字典服务,也就是我们常用的分布式缓存中间件,它的本质就是NoSQL数据库。我们都知道数据库是用来存储数据的,Redis还是在内存中的数据库,单台机器的内存是有限的,所以说Redis集群是为了扩展单节点Redis的存储能力。

Redis Cluster 是不保证Redis高可用的,保证Redis高可用的是主从复制加哨兵模式。

虽说Redis Cluster不能保证Redis的高可用,但是可以通过分区来提供一定程度的可用性。在生产环境中,当某个节点宕机或者不可达的情况下可以继续处理命令。

Redis Cluster的优势:

  • 自动分割数据到不同的节点上。
  • 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。

2 Redis Cluster 哈希槽的应用

Redis Cluster并没有使用一致性hash,而是引入了 哈希槽的概念

Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽。集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么节点 A 包含 0 到 5500号哈希槽,节点 B 包含5501 到 11000 号哈希槽,节点 C 包含11001 到 16384号哈希槽。

image.png

那么使用哈希槽有什么优势呢?

那就是扩缩容,我们使用哈希槽时,增加减少Redis节点就会很方便,如果我们想要新添加个节点D, 我们只需要从之前的节点分部分哈希槽到节点D上。 如果我想移除某个节点,只需要将该节点中的哈希槽移到另外两个节点上,然后将该节点从集群中移除即可.。

从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加或是删除节点都不会造成集群的不可用,这样就实现了动态扩缩容。

小知识:为什么Redis中哈希槽的个数是16384?

理论上CRC16算法可以得到2的16次方个数值,其数值范围在0-65535之间,取模运算key的时候,应该是crc16(key)%65535,但是却设计为crc16(key)%16384,原因是作者在设计的时候做了空间上的权衡,觉得节点最多不可能超过1000个,同时为了保证节点之间通信效率,所以采用了2^14。

3 一致性哈希是什么?

要想知道一致性哈希是什么,我们就得首先了解一下哈希,哈希就是哈希算法。

哈希算法最重要的特点就是:

  • 相同的输入一定得到相同的输出;
  • 不同的输入大概率得到不同的输出。

我们一般吧不同的输入得到相同输出,称为哈希碰撞

小知识1: 哈希碰撞是否能够避免呢?

不能,哈希碰撞是一定会出现的,因为输出的字节长度是固定的,但输入的数据长度是不固定的,有无数种输入。哈希算法是把一个无限的输入集合映射到一个有限的输出集合,必然会产生碰撞。

小知识2:是否能够直接使用哈希确定key存放在哪个节点呢?

当有三台机器时我们使用hash(key) % 3

如果机器数不变是可以的,但是如果需要增加机器就完犊子了,假设加一台机器算法变为Hash(key) % 4,原本Hash(key)是4的是放在机器1的,现在变为了机器0,这样就会引起大量的缓存穿透,造成雪崩。

这也就是说,为什么我们在有了哈希算法,还得再搞出个一致性哈希算法的原因

1997年,麻省理工学院的 Karger 等人提出了一致性哈希算法,为的就是解决分布式缓存的问题。

一致性hash是一个0到2的32次方的闭合环型结构,占用4个字节,拥有2的32次方个桶空间,每个桶空间可以存储很多数据。

一致性哈希是采用的是如下步骤:

  1. 对节点进行hash,通常使用其节点的ip或者是具有唯一标示的数据进行hash(ip),将其值分布在这个闭合圆上。
  2. 将存储的key进行hash(key),然后将其值要分布在这个闭合圆上。
  3. 从hash(key)在圆上映射的位置开始顺时针方向找到的一个节点即为存储key的节点。如果到圆上的0处都未找到节点,那么0位置后的顺时针方向的第一个节点就是key的存储节点。

image.png

添加节点,如果现在节点A和节点C中间增加一个节点D,那么在节点A和节点C之间的这些数据要存储的节点就会有所变化。删除节点就会把当前节点所有数据加到它的下一个节点上。这样会导致下一个节点使用率暴增,可能会导致挂掉,如果下一个节点挂掉,下下个节点将会承受更大的压力,最终导致集群雪崩。

image.png

4 哈希槽和一致性哈希对比

了解了一致性哈希,想必大家也就知道了Redis为什么会放弃掉一致性哈希而使用哈希槽了吧,下面我们在简单总结一下。

  • 一致性哈希的节点分布基于圆环,无法很好的手动设置数据分布,比如有些节点的硬件差,希望少存一点数据,这种很难操作。而哈希槽可以很灵活的配置每个节点占用哈希槽的数量
  • 一致性哈希的某个节点宕机或者掉线后,当该机器上原本缓存的数据被请求时,会从数据源重新获取数据,并将数据添加到失效机器后面的机器,这个过程被称为 "缓存抖动" ,而使用哈希槽的节点宕机,会导致一定范围内的槽不可用,只能通过主从复制加哨兵模式保证高可用。
  • 真是基于一致性哈希的特点,当某台机器宕机时,极易引起雪崩,如上述介绍中删除节点。
  • Redis Cluster的槽位空间是可以用户手动自定义分配的,类似于 windows 盘分区的概念,可以手动控制大小。
  • 相对于哈希槽,一致性哈希算法更复杂

正是基于这些特点,Redis取舍后选择了哈希槽。