Redis的集群方案总共有3种:
1.主从同步
2.哨兵模式
3.分片集群
一.Redis的主从同步
单节点Redis的并发能力是有限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离,一般都是一主多从,主节点负责写数据,从节点负责读数据
主从同步的方式:
1.全量同步:
第一步从节点执行replicaof命令建立,请求主节点数据同步,然后主节点判断是否是第一次同步,如果是第一次,则返回master的数据版本信息,然后从节点保存版本信息,然后主节点执行bgsava,生成RDB,然后发送RDB文件,从节点清空本地数据,加载RDB文件,然后从节点清空本地数据,加载RDB文件,这时候是不是就完成了主从同步呢?其实这里还是有问题的,如果主节点再进行主从同步的时候又有数据进行了修改,那这部分数据并没有同步到从节点,为了解决这个问题,引入了repl_baklog它会记录RDB期间的所有命令,然后发送repl_backlog中的命令,然后从节点执行接收到的命令。
这里还有两个问题:
(1)如何判断数据是否是第一次同步
主节点有一个replid,从节点有一个replid,当进行数据同步的时候,如果这两个节点的replid不同,那么就是第一次数据同步,第一次数据同步完后,主节点会把自己的replid发送给一份给从节点,
当进行第二次同步数据的时候,两个replid值就一样了,然后再进行数据同步的时候,就不会执行bgsave,生成RDB文件了,而是直接通过repl_baklog
(2)当进行第二次数据或者更多次数据同步的时候,如何判断应该同步那一部分新修改的数据?
我们先来介绍一个概念:offset 偏移量,随着记录在repl_baklog中的数据增多而逐渐增大,slave完成同步时也会记录在当前同步的offset,如果slave的offset小于master的offset,说明slave的数据落后于master,需要更新
举个例子再进行第一次数据同步的时候,假设主节点的offset为50,在数据同步的时候,主节点又有新的数据修改,第一次数据同步结束,从节点offset为50,但主节点offset为80.那么就会把多余的30数据进行同步
2.增量同步:
二.哨兵模式:
1.含义:
哨兵模式专注于对 Redis 实例(主节点、从节点)运行状态的监控,并能够在主节点发生故障时通过一系列的机制实现选主及主从切换,实现故障自动转移和恢复,确保整个 Redis 系统的可用性
Sentinel基于心跳的机制监测服务状态,每隔1秒向集群中的每个实例发送ping命令
(1)主观下线:如果某sentinel节点发现某实例未在规定时间内响应,则认为改实例主观下线
(2)客观下线:若超过指定数量的sentinel都认为该实例主观下线,则改实例客观下线
2.哨兵选主规则:
(1)首先判断主从节点断开时间长短,如超过指定时间则排除改节点
(2)然后判断从节点的slave_priority值,越小优先级越高
(3)如果slave_prority一样,则判断slave节点的offset值,越大优先级越高
(4)最后判断slave节点的运行id大小,越小优先级越高
3.Redis集群脑裂是什么?该如何实现
集群脑裂是由于主节点和sentinel处于不同的网络分区,使得sentinel没有能够心跳感知到主节点,所以又选出了一个从节点为主节点
集群脑裂带来的问题:
客户端 写入数据还是会写到老的主节点,新节点无法同步数据,当网络恢复后,sentinel会将老的主节点将为从节点,这时再从新的主节点同步数据,就会导致数据丢失
解决:我们可以修改redis的配置,可以设置最少的从节点数量以及缩短主从数据同步的延迟时间,达不到要求就拒绝请求,可以避免大量的数据丢失
三.分片集群架构:
1.主从和哨兵可以解决高可用,高并发读的问题,但是没有解决海量数据存储问题和高并发写问题
集群里有多个master,每个master保存不同数据,相较于单个master,集群能存储更多的数据
每个主节点有多个从节点
主节点之间通过ping监测彼此健康状态
客户端请求可以访问集群里任意节点,最终都会转发到正确节点
2.Redis分片集群中数据是怎么存储和读取的
(1)Redis分片集群里引入了哈希槽的概念,Redis集群里有16384个哈希槽
(2) 将16384插槽到不同的实例
(3)读写数据:根据key的有效部分计算哈希值,对16384取余(有效部分,如果key前面有大括号,大括号的内容就是有效部分,如果没有,则以key本身作为有效部分)余数作为插槽,寻找插槽所在的实例。
四.Redis快的原因
1.内存访问
2.单线程,避免了线程的上下文切换
3.IO多路复用
下面我们来重点讲解一下IO多路复用
Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度,I/O多路复用模型主要就是实现了高效的网络请求
用户空间和内存空间
用户空间和内核空间:
linux系统中一个进程使用的内存情况划分为两部分:内核空间、用户空间
用户空间:只能执行受限的命令,而且不能直接调用系统资源,必须通过内核提供的接口
内核空间:可以执行特权命令,调用一切系统资源
Linux系统会在用户空间和内核空间都加入缓冲区
写数据时,把用户缓冲数据拷贝到内核缓冲区,然后写入设备
丢数据时,要从设备读取数据到内核缓冲区,然后拷贝到用户缓冲区
这里举个例子:当我们发送一条消息给对方的时候,我们发送的消息在用户缓冲区,然后到了内核缓冲区,然后再到硬件设备(网卡),通过网卡发给对方,然后对方回的消息会通过网卡放入内核缓冲区,然后到
阻塞IO:
阶段一:(1)用户进程尝试读取数据(比如网卡数据)
(2)此时数据尚未到达,内核需要等待数据
(3)此时用户进程处于阻塞状态
阶段二:(1)数据到达并拷贝到内核缓冲区,代表已就绪
(2)将内核数据拷贝到用户缓冲区
(3)拷贝过程中,用户进程依然阻塞等待
(4)拷贝完成,用户进程阻塞解除,处理数据
非阻塞IO:
阶段一:
(1)用户进程尝试读取数据(比如网卡数据)
(2)此时数据尚未到达,内核需要等待数据
(3)返回异常给用户进程
(4)用户进程拿到error后,再次尝试去读
(5)循环往复,直到数据就绪
阶段二:
(1)将内核数据拷贝到用户缓冲区
(2)拷贝过程中,用户进程仍然阻塞等待
(3)拷贝完成,用户进程解除阻塞,处理数据
可以看到非阻塞IO模型中,用户进程在第一个阶段是非阻塞,第二个阶段是阻塞状态。虽然是非阻塞,但性能并没有得到提高,而且忙等机制会导致CPU空转,CPU使用率暴增。
IO多路复用:
是利用单个线程来同时监听多个socket,并在某个Socket可读,可写时得到通知,从而避免无效的等待,充分利用CPU资源
阶段一:
(1) 用户进程调用select,指定要监听的Socket集合
(2)内核监听对应的多个socket
(3)任意一个或多个socket数据就绪则返回readable
(4)此过程中用户进程阻塞
阶段二:
(1)用户进程找到就绪的socket
(2)依次调用recvform读取数据
(3)内核将数据拷贝到用户空间
(4)用户进程处理数据
select和poll只会通知用户进程有Socket就绪,但不确定具体是那个socket,需要用户进程逐个遍历Socket来确认
epoll则会通知用户进程Socket就绪的同时,把已就绪的Socket写入用户空间。
Redis网络模型
使用I/O多路复用结合事件的处理器来应对多个Socket请求
(1)连接应答处理器
(2)命令回复处理器,在Redis6.0之后,为了提升更好的性能,使用了多线程来处理回复事件
(3)命令请求处理器,在Redis6.0之后,将命令的转换使用了多线程,增加命令转换速度,在命令执行的时候,依然是单线程