Redis集群原理解析

一、单机Redis存在的问题

问题1:数据丢失问 解决方案:利用RDB和AOF实现数据的持久化
问题2:并发能力弱 解决方案:搭建主从集群 ,实现主从分离
问题3:存储空间小 解决方案:搭建分片集群 ,利用槽机制 实现动态扩容
问题4:故障恢复 解决方案:利用Redis哨兵机制,实现健康检测和自动恢复

二、主从集群解析

2.1 定义

将一台Redis服务器的数据,复制到其他的Redis服务器。前者为主节点 ,后者为从节点

2.2 特点

  • 数据的复制是单向的,只能从主节点到从节点。Master以为主,Slave以为主;
  • 默认情况下,每台Redis都是主节点;
  • 一个主节点可以有多个从节点(或者没有从节点),一个从节点只能由一个主节点;
  • Redis主从复制支持主从复制从从复制。后者是Redis后续版本新增功能的。

二八定律:80%的情况下是在进行读操作,20%是在进行写操作

2.3 主从复制的作用

java 复制代码
1. 数据冗余:主从复制实现了数据的"热备份",是持久化之外的一种数据冗余方式;
2. 故障恢复:当主节点出现问题时,可由从节点提供服务,实现快速的故障恢复
3. 负载均衡:在主从复制的基础上,配合"读写分离",由主节点提供写功能,从节点提供读功能分担服务器的负载。尤其是在"写少读多"的场景,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
4. 高可用(集群)基石:主从复制还是"哨兵"和"集群"能够实施的基础。

2.4 数据同步机制

  1. Slave启动成功连接到master后会发送一个Sync同步命令,包括ReplictId和OffSet信息;
  2. Master接到命令,执行bgsave命令启动后台的存盘进程,同时收集所有收到的用于修改数据集命令,在后台进程执行完毕后,master将传送整个数据文件到slave,并完成一次完全同步,同时主服务器不会拒绝客户端的读写,将客户端的写命令写入到缓冲区中;【全量同步
  3. Master发送完快照数据后,会将缓冲区中的命令发送给slave服务器,slave服务器开始执行slave命令;
  4. 接下来,每当主服务器收到一条写命令后,就会将写命令同步给从服务器,保证主从服务器数据的一致。【增量同步 】。
    其中ReplictId和Offset用于增量同步时,判断Master和Slave两者之间的数据版本以及差异等问题。

全量复制:slave服务在接收到数据库文件数据后,将其存盘并加载到内存中;
增量复制:Master继续将"新的"所有收集到的修改命令一次传给slave,完成同步

注意】:只要重新连接到Master,一次完全同步(全量复制)将会被自动执行。

2.5 两种配置模式(配置主机和从机)

配置文件配置:主机断开连接,从机依旧连接到主机,但是没有写操作。一旦主机回来了,从机依然接收主机写的信息。
命令行配置:如果从机重启了,就会变成主机。

三、哨兵(Sentinel)集群模式

解决的问题:一旦主机宕机后,能主动从从节点中选举出主机。
一对多(一个哨兵监控多个Redis实例):哨兵本质是一个独立进程,可独自运行。哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

3.1 主要流程

  1. 哨兵发送命令,让Redis服务器返回监控其运行状态,包括Master server和Slave server;
  2. 当哨兵监测到master宕机后,会自动将slave切换到master,通过发布订阅模式通知其他的从机修改配置文件,切换主机。

存在的问题:单个哨兵如果出现问题,那么将无法监控Redis运行状态,就无法在主机出现故障时,及时的切换
解决方法:多对多模式,即多个sentinel哨兵监控多个Redis实例。

3.2 哨兵功能

java 复制代码
1. 监控(monitor):哨兵会不断的检查主节点和从节点是否运作正常
2. 自动故障转移(Automatic failover): 当"主节点"不能正常工作时,哨兵会开始"自动故障转移操作",它会将失效主节点的其中一个"从节点升级为新的主节点",并让其他从节点改为复制新的主节点;
3. 配置提供者(Configuration provider):客户端在初始化时,通过连接哨兵来获得当前Redis服务的主节点地址
4. 通知:哨兵可以将故障转移的结果发送给客户端

其中,每个哨兵监控所有的主机和从机,哨兵之间也会相互监控。

3.3 整体运行机制

3.3.1 判断Master主节点故障

主观下线:当主服务器宕机后,假设哨兵1先检测到这个结果,系统并不会马上进failover(重新选举)过程,仅仅是哨兵1主观地认为主服务不可用,这个现象为主观下线
客观下线:当后面的哨兵也监测到主服务器不可用且数量达到一定值 时,那么哨兵之间就进行一次投票,投票的结果由一个哨兵发起,进行failover操作,切换成功后,就会发布订阅模式 让各个哨兵监控的从服务器切换主机,这个过程称为客观下线

3.3.2 选举新的Master节点

出现故障后,就需要选取新的Master节点。选举依据为:

java 复制代码
排除原则:
1. 排除已经宕机的slaves;
2. Sentinel leader会向所有的slaves发送命令,响应慢(回复ping命令时间大于五秒钟)的排除;
3. 与原Master通信慢(与失效服务器连接断开的时长超过down-after选项指定的时长十倍)的排除;

优先原则:
5. 判断slave节点的save-priority值, 越小优先级越高 -> 选择优先级高的slave节点;
6. 若优先级相同,选择offset大的节点, 越大数据复制的最完整 -> 选择offset大的slave节点;
7. 若offset相同,则选择runid最小的(启动最早的节点) -> 选择runid最小的slave节点

3.3.3 实现故障转移

新的Master节点选举完成后,需要更新每个节点的主从配置信息。包括故障的Master节点和Slave节点。所谓的更新,即故障转移机制,整理流程为:

java 复制代码
1. 首先, sentinel给备选的slave节点发送salveof no one命令,使该节点成为Master节点;
2. 其次, sentinel给其他的slave节点发送salve of [master节点的ip和port],让这些slave成为新master的从节点,开始新的master同步数据;
3. 最后,sentinel将故障节点标记为slave,故障节点恢复后会自动成为新的master的slave节点。

四、分片集群(多个主节点)解析

4.1 背景

哨兵集群虽然可以解决高可用和高并发读的问题。但仍然存在两个问题:

  1. 大数据量的存储问题
  2. 高并发写的问题

因此,使用分片集群可以解决上述问题。

4.2 特点

  1. 数据分布式存储。每个Master存储数据部分数据;
  2. 健康状态自监测。master之间每隔一段时间会进行通信,若某一个master发生故障,可进行故障转移,取代了哨兵机制;
  3. 读写分离。单master和多slave之间也满足了读写分离。

4.3 集群数据分区方案

4.3.1 哈希值 % 节点数

过程:对key进行hash,利用hash值对节点数量取余,映射到对应节点上。
缺点:一旦其中某个master宕机,每个key对应的"映射关系"需要重新计算,短时间造成数据查询错误,导致数据库的压力增大,会影响所有数据,一般采用翻倍扩容方式

4.3.2 一致性哈希算法(自动缓存转移) + 虚拟节点(自动负载均衡)

原理:将多个master节点均匀的分布在一个圆环上,对key进行hash,判断hash落在哪个点上,然后顺时针旋转,去最近的master节点去查询。这样就算某一个master宕机,也只有1/3的数据失效。当增加或者删除节点时,部分节点信息会迁移到附近节点上。
缺点:当节点数量较少时,增加或删除节点,对单个节点的影响可能很大,造成数据的严重不平衡【影响单个节点的所有数据】
解决方案: 使用虚拟节点 。在相邻节点之间增加非相邻的虚拟节点。例在node1和node2之间增加node3、node4等。当某个master宕机后,失效的数据远小于1/3.
缺点:一致性hash在扩容时还是会导致一个节点的部分时间不可用

4.3.3 虚拟槽分区

虚拟槽中的槽就是大量虚拟节点的抽象化,将原来的虚拟节点变成一个槽,Redis内置是有16383个槽。每个Redis节点存储一部分虚拟槽。将redis集群分成16384个槽,每个master1节点负责一些槽。

java 复制代码
【特点:】key不是与节点绑定,而是与虚拟槽点绑定。redis会根据【key的有效部分】计算插槽值,主要分为两种情况:
- key中包含"{}",且"{}"中至少包含一个字符,使用"{num}"使用num来计算插槽值slot;
- 否则,使用key来计算插槽值slot;
场景:计算某个key在哪个实例?
1. 将16384个插槽分配到不同的实例上;
2. 根据key的有效部分计算哈希值,对16384取余;
3. 余数作为插槽,寻找插槽所在的实例即可。

【好处:】
4. 方便的添加或移除节点;
5. 对应槽的采用【直接复制,槽不变化】数据过去显然比rehash快很多

为什么是16384(2^14)个?

答:因为redis发送心跳包时,会将所有槽信息放到心跳包中,发送给其他的redis来交换集群信息。CRC16算法产生的hash值有16bit,但是redis cluster实例建议不超过1000个,超过1000个容易发生网络阻塞,而在redis实例不超过1000个的情况下,将redis集群划分成16384个槽占用的大小的是2k,是比较节省内存空间的,否则使用16bit占用内存大小为16k,完全没有必要。

五、哨兵模式和集群模式的区别

5.1 哨兵模式

优点:高可用,在主节点出现故障时实现故障的转移
缺点:集群容量一旦达到上限,在线扩容十分麻烦,无法做到水平拓展

5.2 集群模式

优点:可以横向扩展
缺点:客户端实现复杂,且slave节点不提供读写的能力,仅仅是一个冷备节点

5.3 区别

  1. 哨兵模式监控权交给了哨兵系统;集群模式中工作节点自己做监控
  2. 哨兵模式发起选举是选举一个leader哨兵节点来处理故障转移;集群模式在节点中选举一个新的主节点来处理故障的转移。
相关推荐
ygl615037328 分钟前
Vue3+SpringBoot3+Sa-Token+Redis+mysql8通用权限系统
java·spring boot·vue
Code哈哈笑31 分钟前
【Java 学习】构造器、static静态变量、static静态方法、static构造器、
java·开发语言·学习
是老余33 分钟前
Java三大特性:封装、继承、多态【详解】
java·开发语言
鸽鸽程序猿33 分钟前
【JavaEE】Maven的介绍及配置
java·java-ee·maven
尘浮生1 小时前
Java项目实战II基于微信小程序的南宁周边乡村游平台(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·微信小程序·小程序·maven
耀耀_很无聊5 小时前
第1章 初识SpringMVC
java·spring·mvc
麻衣带我去上学5 小时前
Spring源码学习(一):Spring初始化入口
java·学习·spring
东阳马生架构5 小时前
MySQL底层概述—1.InnoDB内存结构
java·数据库·mysql
手握风云-6 小时前
数据结构(Java版)第一期:时间复杂度和空间复杂度
java·数据结构
坊钰7 小时前
【Java 数据结构】时间和空间复杂度
java·开发语言·数据结构·学习·算法