一、Redis Sentinel
1.1、一主多从
Redis普通的一主多从模式,一主多从模式指 Redis 主节点以单个节点的形式存在,这个主节点可读可写,上面存储数据全集。在3.0版本之前,Redis 只能支持单机模式,出于可靠性考量,通常单机模式为“1主 N 备”的结构,如下所示:
需要说明的是,即便有很多个 Redis 主节点,只要这些主节点以单机模式存在,本质上仍为单机模式。单机模式比较简单,足以支撑一般应用场景,但单机模式具有固有的局限性:不支持自动故障转移,扩容能力极为有限(只能 Scale Up,垂直扩容),存在高并发瓶颈。
1.2、Sentinel模式
Redis 单机模式下,即便是“1主 N 备”结构,当主节点故障时,备节点也无法自动升主,即无法自动故障转移(Failover)。故障转移需要“哨兵”Sentinel 辅助,Sentinel 是 Redis 高可用的解决方案,由一个或者多个 Sentinel 实例组成的系统可以监视 Redis 主节点及其从节点,当检测到 Redis 主节点下线时,会根据特定的选举规则从该主节点对应的所有从节点中选举出一个“最优”的从节点升主,然后由升主的新主节点处理请求。具有 Sentinel 系统的单机模式示意图如下:
哨兵模式的特点
- 故障检测:哨兵能够监控节点的状态,并在节点不可用时进行通知。
- 自动故障转移:在主节点故障时,哨兵会自动进行故障转移,保证系统的高可用性。
- 通知机制:哨兵可以配置通知机制,在发生故障转移或其他重要事件时通知管理员。
哨兵模式的局限性
- 不支持自动分片:哨兵模式不提供数据分片功能,所有数据都存储在一个主节点上。
- 写能力受限:由于所有写操作都在单个主节点上进行,写能力受限于单个节点的性能。
二、Redis Cluster
Sentinel虽然实现了master的故障转移,但实际的结构是单master架构,单master架构虽然简单,但瓶颈明显。一是容量问题,在一些应用场景下,数据规模可达数十 G,甚至数百 G,而物理机的资源却是有限的,内存无法无限扩充;二是并发性能问题,Redis 号称单实例10万并发,但也仅仅是10万并发。鉴于单机模式的局限性,历时三年,Redis Cluster 应运而生。
Redis 集群是一个提供数据分片(sharding)和高可用性的解决方案。在集群模式下,数据会被分散存储在多个节点上,每个节点只保存部分数据。这样的设计可以提升系统的性能和容量。
2.1 Redis Cluster 特点
自3.0版本起,Redis 官方推出了一个原生的分布式方案—— Redis Cluster。它是一个分布式、容错的 Redis 实现。Redis Cluster中不存在中心节点或者代理节点,集群主要设计目标之一是实现线性可扩展性。
Redis Cluster 具有以下特点:
- 节点互通:所有的 Redis 节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽;
- 去中心化:Redis Cluster 不存在中心节点,每个节点都记录有集群的状态信息,并且通过 Gossip 协议,使每个节点记录的信息实现最终一致性;
- 客户端直连:客户端与 Redis 节点直连,不需要中间 Proxy 层,客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可;
- 数据分片:Redis Cluster 的键空间被分割为 16384 个 Slot,这些 Slot 被分别指派给主节点,当存储 Key-Value 时,根据 CRC16(key) Mod 16384的值,决定将一个 Key-Value 放到哪个 Slot 中;
- 多数派原则:对于集群中的任何一个节点,需要超过半数的节点检测到它失效(pFail),才会将其判定为失效(Fail);
- 自动 Failover:当集群中某个主节点故障后(Fail),其它主节点会从故障主节点的从节点中选举一个“最佳”从节点升主,替代故障的主节点;
- 功能弱化:集群模式下,由于数据分布在多个节点,不支持单机模式下的集合操作,也不支持多数据库功能,集群只能使用默认的0号数据库;
- 集群规模:官方推荐的最大节点数量为 1000 个左右,这是因为当集群规模过大时,Gossip 协议的效率会显著下降,通信成本剧增。
- 多键操作限制:由于数据分布在不同的节点上,多键操作(比如 MSET、MGET、SUNION 等)要求所有相关的键必须在同一节点上。
- 数据迁移复杂性:当集群进行扩容或缩容时,数据迁移过程可能会比较复杂。
2.2 Redis-Cluster分片
- Redis 集群实现的基础是分片,即将数据集有机的分割为多个片,并将这些分片指派给多个 Redis 实例,每个实例只保存总数据集的一个子集。利用多台计算机内存和来支持更大的数据库,而避免受限于单机的内存容量;通过多核计算机集群,可有效扩展计算能力;通过多台计算机和网络适配器,允许我们扩展网络带宽。
- 基于“分片”的思想,Redis 提出了 Hash Slot。Redis Cluster 把所有的物理节点映射到预先分好的16384个 Slot 上,当需要在 Redis 集群中放置一个 Key-Value 时,根据 CRC16(key) Mod 16384的值,决定将一个 Key 放到哪个 Slot 中。
2.3、节点通信基础Gossip
Redis Cluster 中的每个 Redis 实例监听两个 TCP 端口,6379(默认)用于服务客户端查询,16379(默认服务端口+10000)用于集群内部通信。集群中节点通信方式如下:
每个节点在固定周期内通过特定规则选择几个节点发送 Ping 消息,接收到 Ping 消息的节点用 Pong 消息作为响应。
集群中每个节点通过一定规则挑选要通信的节点,每个节点可能知道全部节点,也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终它们会达到一致的状态。当节点故障、新节点加入、主从关系变化、槽位信息变更等事件发生时,通过不断的 Ping/Pong 消息通信,经过一段时间后所有的节点都会知道集群全部节点的最新状态,从而达到集群状态同步的目的。
Gossip 协议的主要职责就是信息交换。信息交换的载体就是节点彼此发送的Gossip 消息,常用的 Gossip 消息可分为:Ping 消息、Pong 消息、Meet 消息、Fail 消息。
Meet 消息:用于通知新节点加入。消息发送者通知接收者加入到当前集群,Meet 消息通信正常完成后,接收节点会加入到集群中并进行周期性的 Ping、Pong 消息交换;
Ping 消息:集群内交换最频繁的消息,集群内每个节点每秒向多个其它节点发送 Ping 消息,用于检测节点是否在线和交换彼此状态信息。Ping 消息发送封装了自身节点和部分其它节点的状态数据;
Pong 消息:当接收到 Ping、Meet 消息时,作为响应消息回复给发送方确认消息正常通信。Pong 消息内部封装了自身状态数据。节点也可以向集群内广播自身的 Pong 消息来通知整个集群对自身状态进行更新;
Fail 消息:当节点判定集群内另一个节点下线时,会向集群内广播一个 Fail 消息,其他节点接收到 Fail 消息之后把对应节点更新为下线状态。
由于集群内部需要频繁地进行节点信息交换,而 Ping/Pong 消息携带当前节点和部分其它节点的状态数据,势必会加重带宽和计算的负担。Redis 集群内节点通信采用固定频率(定时任务每秒执行10次),因此,节点每次选择需要通信的节点列表变得非常重要。通信节点选择过多虽然可以做到信息及时交换但成本过高。节点选择过少则会降低集群内所有节点彼此信息交换的频率,从而影响故障判定、新节点发现等需求的速度。因此 Redis 集群的 Gossip 协议需要兼顾信息交换实时性和成本开销。
2.4、手动搭建Redis Cluster
2.4.1、机器规划
3台服务器,每台服务器开启2台实例构建基础主从。
服务器采用Rocky9.4,Redis版本为6.2.4
地址规划与结构图如下:
在每个node上设置主机名解析:
2.4.2、集群准备
根据前面文章《Redis系列二---轻松玩转Redis从安装到多实例的趣味之旅》的方法在三个节点上分别运行两个实例,分别监听6379和6380两个端口
2.4.3、启动Redis实例
在启动Redis实例时,会按照Redis服务配置文件的配置项判断是否启动集群模式,流程图如下:
修改redis配置文件,启动集群模式
集群模式启动后,进程名称后会加上[cluster]的字样
同时,查看集群节点配置文件,会生成一组集群信息,每个Redis实例都是不同的
2.4.4、加入集群
现在虽然每个实例都启动成功了,但是彼此之间并没有任何联系。
所以下一步需要将6个实例加入至一个集群中,如下操作示例
查看当前集群所有的节点
查看节点端口监听,可以发现Gossip监听的1000+端口出现了,此时代表集群各个实例之间已经互相通信了。
2.4.5、配置主从关系
目前6个实例之间并没有任何主从关系,现在进行主从关系配置,记录下集群cluster node命令输出的node-id信息,只记录6379端口主节点的ID即可
首先是node1的6380,将它映射到node2的6379上
然后是node2的6380映射到node3的6379上
最后是node3的6380映射到node1到6379上
查看集群节点信息
2.4.6、手动分配槽位
接下来开始分配槽位,为了考虑后面到写入操作能分配均匀,槽位也要进行均匀分配到三个master上,计算每个master分配多少个槽位。
槽位分配规划,槽位号从0开始,到16383结束,共16384个槽位:
节点 | 槽位 |
node1:6379 | 0-5461 |
node2:6379 | 5461-10922 |
node3:6379 | 10922-16384 |
分配操作命令
检查槽位是否分配正确
2.4.7、检查集群状态
使用cluster info命令检查集群状态是否ok
MOVED重定向
-c参数
客户端连接时加上-c参数即可自动连接moved指令给的新节点进行写入
2.4.8、故障转移
故障模拟
模拟node1的6379下线宕机,此时应该由node3的6380接替它成为新的master
登录集群任意节点查看目前集群节点信息
模拟故障恢复
重新启动node1的6379
登录node1的6379,查看其主从状态,可以看到重新启动后node1的6379实例当做了node3 6380的备份
欢迎关注作者的公众号,公众号每天分享运维干货文章