Redis---集群模式

发布于:2025-09-15 ⋅ 阅读:(25) ⋅ 点赞:(0)

一、集群模式概述

首先,Redis的集群是指的狭义上的集群,指使用了分片技术将数据分别存储到了不同的主机上,而广义上的集群则只要使用了分布式架构就可以。

Redis集群模式解决的是单个服务器的内存已经不足以存储所有的数据,需要将数据“分片”,将分片的数据分布到不同主机上,同时Redis集群也涉及到了故障转移功能,这里和哨兵模式有些类似,也需要进行投票。

二、数据分片算法

一般有三种,理想的算法是合理的将数据均匀分布到主机上,而且后续扩容的主机也可以分担数据压力,下面说的算法中,前两种算法适合于特定的情况,并不是Redis官方推荐的算法,最后一种才是主流的算法。

1.哈希求余算法

把Key映射为一个整数(如采用Md5),然后用这个整数对分片(主机数)个数进行求余,得到要存储到哪个主机上。

优点很明显,在不考虑后续扩容的情况下,这种算法很简单,而且也能做到将数据近似均匀的分布到所有主机上。

缺点:在后续引入新主机来扩容时,需要将原本的Key映射的整数再对主机数进行求余,这样必然会导致大量数据进行迁移,对性能损耗很大,扩容后,这些分片上的数据是均匀的。

这种情况适合于扩容情况较少的情况。

2.一致性哈希算法

这个将int表示的范围(0-2^32-1)映射到一个环形区域上,然后采用hash算法得到一个整数,根据这个整数放到对应位置即可。这个环形区域则由分片们平分,每个负责一段。

优点:在后续引入新的分片来扩容时,只需要将新分片插入即可,比如接收最后一个分片负责的一半区域,这样这需要迁移这一段数据即可,无需动全部数据,扩容的压力会小很多。

缺点:由于只是负责了最后一个分片的一部分数据,所以无法达到理想算法的数据均匀分布,分片的压力不同,维护起来就比较麻烦。

3.哈希槽算法(Redis官方使用的)

它的核心思想可以使用下面的式子表示:

hash_slot = cr1c6(Key) % 16384 

其中crc16是一种哈希算法,将key映射为一个整数。16384表示哈希槽的数量。

流程大概为在接收到一个新数据后,先采用crc16算法将key映射为一个整数,在对16384进行取余,再根据这个余数将这个数据放到对应的哈希槽上,而每一个分片都维护一些哈希槽,这些哈希槽不一定是连续的(和后面的扩容有关),但是每个分片维护的哈希槽数量是一致的,这保证了数据均匀分布。然后根据哈希槽找到对应的分片,将数据存上去即可。

后续扩容的化,默认情况下是将每一个原有分片的一部分哈希槽给新节点,比如redis1哈希槽是0-4096,redis2是4097-8192,redis3是8193-12289,redis4是12290-16383,后续引入一个新的分片redis5,就可以从每一个原有分片上取最后大概一千个哈希槽给redis5,这样数据迁移的成本会小很多,迁移后,redis5的哈希槽数目就不是连续的,而是一段一段的,当然也可以手动指定只迁移哪些分片上的数据。

至于为什么使用16384作为哈希槽数量,原因是1.在节点中使用心跳包来通信,哈希槽的占用情况则使用一个位图来表示,也就是16384个比特位,也就是2*8*1024=2KB,这样是比较合适的大小,因为如果过大的话,节点之间的通信压力就会大很多。2.16384对应常见的Redis集群规模也是合适的,一般都是几十到几百的集群规模,很少有上千的,16384个哈希槽分配也是够用的,不会出现分片个数大于哈希槽数的情况。

三、集群模式下的故障转移

在集群模式中,每个节点都会随机的向其他的一些节点发送心跳包,如果在规定时间内没有接收到回复,就认为该节点可能已经下线,标记为“主观下线”,同时发送信息询问其他节点是否认为该节点下线,此时会进行投票,但是只有主节点才有投票权,超过半数主节点都认为该节点都已经下线后,就会标记其为“客观下线”,如果下线的节点是从节点倒问题不大,如果是主节点,之后进行新的主节点的选举过程。

在确认该节点为主节点且已经下线后,该主节点下的所有从节点会进行一个随机时间的休眠,这是为了避免过多的从节点同时发起竞选请求,休眠时间为 [0-500]ms+排名*1000ms,其中排名和offset大小负相关,offset越大排名越靠前,这样让offset更大的节点休眠的时间更小。

在从节点醒来后,会向主节点发送竞选请求,主节点也会投第一个向自己发送请求的从节点,在规定的时间内某个从节点收到超过半数主节点的投票后,会向所有节点广播,通知它们自己是新的主节点,之后执行salveof no one命令,让自己成为独立节点,其他从节点再根据新的集群结构来改变为新的从属关系,自此,Redis集群的自动故障转移就算完成了。

一些特殊的极端情况:

1.主从节点同时全挂了,会导致没有合适的从节点来接收导致数据丢失。

2.只有主节点而且挂了,本质和上一种情况一样。

3.超过半数的maser同时挂了,这导致一直没有从节点的票数达到半数以上,从而一直没有新节点来接替。