目录
在Redis中提供的集群方案总共有三种
主从复制
单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。
其中主节点,主要负责客户端的写操作,比如增删改的操作,从节点负责客户端的读操作,因为Redis一般都是读多写少,所以现在我们让多个从节点负责读操作,这样就增加了Redis的并发能力,假如一台Redis的并发读是10w,现在有两台,就是20w。
但是需要注意,当主节点写了数据之后,需要把数据同步到从节点才行,必须保证主从节点的数据同步,这样才能真正意义上实现读写分离
主从数据同步原理
主从全量同步
步骤如上图所示,但是依然会有几个问题
1.master如何判断是第一次同步?
这时候需要提及两个概念
Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid
offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大,可以理解为一个自增的整数值。slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
答:当从节点发起请求数据同步时就会把自己的replid发送给主机master,然后主节点用自己的replid对比slave发送的replid,如果不一样,就会说明是第一次进行数据同步,主节点这时就会把自己的replid发送给从节点,这个时候,双方的replid就一样了
2.我们通过日志文件repl_baklog同步时,怎么保证同步的数据都是从节点需要的数据呢?
答:在主从进行版本消息同步的时候也会记录当前同步的offset。如果slave的offset小于master的offset,说明slave数据落后于master,需要更新。
主从增量同步(slave重启或后期数据变化)
面试回答
面试官:那你来介绍一下主从同步
候选人:嗯,是这样的,单节点Redis的并发能力是有上限的,要进一步提 高Redis的并发能力,可以搭建主从集群,实现读写分离。一般都是一主多 从,主节点负责写数据,从节点负责读数据,主节点写入数据之后,需要把 数据同步到从节点中
面试官:能说一下,主从同步数据的流程
候选人:主从同步分为了两个阶段,一个是全量同步,一个是 增量同步
全量同步是指从节点第一次与主节点建立连接的时候使用全量同步,流程是 这样的:
第一:从节点请求主节点同步数据,其中从节点会携带自己的replication id 和offset偏移量。
第二:主节点判断是否是第一次请求,主要判断的依据就是,主节点与从节 点是否是同一个replication id,如果不是,就说明是第一次同步,那主节点 就会把自己的replication id和offset发送给从节点,让从节点与主节点的信息 保持一致。
第三:在同时主节点会执行bgsave,生成rdb文件后,发送给从节点去执 行,从节点先把自己的数据清空,然后执行主节点发送过来的rdb文件,这 样就保持了一致 当然,如果在rdb生成执行期间,依然有请求到了主节点,而主节点会以命 令的方式记录到缓冲区,缓冲区是一个日志文件,最后把这个日志文件发送 给从节点,这样就能保证主节点与从节点完全一致了,后期再同步数据的时 候,都是依赖于这个日志文件,这个就是全量同步
增量同步指的是,当从节点服务重启之后,数据就不一致了,所以这个时候,从节点会请求主节点同步数据,主节点还是判断不是第一次请求,不是 第一次就获取从节点的offset值,然后主节点从命令日志中获取offset值之后 的数据,发送给从节点进行数据同步
哨兵模式
主从同步模式有一个致命的缺点,就是无法保证redis的高可用,比如主节点宕机,就丧失了写数据的能力,这个时候
Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵其实也是Redis节点,也是有多台节点组成的一个集群,一般来说至少要部署三台哨兵
哨兵的结构和作用如下:
监控:Sentinel 会不断检查您的master和slave是否按预期工作
自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端
服务状态监控
Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。
哨兵选主规则
首先判断主与从节点断开时间长短,如超过指定值就排该从节点
然后判断从节点的slave-priority值,越小优先级越高
如果slave-prority一样,则判断slave节点的offset值,越大优先级越高
最后是判断slave节点的运行id大小,越小优先级越高。
脑裂问题
如果因为网络问题,主节点还有哨兵都处于不同的网络分区,这个时候如果哨兵检测不到主节点,此时哨兵就会从从节点中选举一个作为新的主节点,
但是旧的主节点还在继续运行,还在和客户端连接,此时就会同时出现两个master,这就是脑裂问题
因为客户端还连接着老的master,会持续的继续写入数据,但是因为网络问题,节点间不能同步数据,此时如果网络恢复了,哨兵会将老的master强制降级为slave,此时他会清空自己的数据并且从新的master中同步数据,那么就会丢失之前脑裂阶段客户端写入的数据
脑裂问题解决方案
redis中可以通过两个配置参数来解决:
min-replicas-to-write 1 表示master最少拥有的salve节点为1个,
min-replicas-max-lag 5 表示数据复制和同步的延迟不能超过5秒
如果不满足要求就会拒绝客户端请求,从而避免了大量的数据丢失
面试回答
面试官:怎么保证Redis的高并发高可用
候选人:首先可以搭建主从集群,再加上使用redis中的哨兵模式,哨兵模式 可以实现主从集群的自动故障恢复,里面就包含了对主从服务的监控、自动 故障恢复、通知;
如果master故障,Sentinel会将一个slave提升为master。 当故障实例恢复后也以新的master为主;同时Sentinel也充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户 端,所以一般项目都会采用哨兵的模式来保证redis的高并发高可用
面试官:你们使用redis是单点还是集群,哪种集群
候选人:我们当时使用的是主从(1主1从)加哨兵。一般单节点不超 过10G内存,如果Redis内存不足则可以给不同服务分配独立的Redis主从节点。尽量不做分片集群。因为集群维护起来比较麻烦,并且集群之间的心跳 检测和数据通信会消耗大量的网络带宽,也没有办法使用lua脚本和事务
面试官:redis集群脑裂,该怎么解决呢?
候选人:这个在项目很少见,不过脑裂的问题是这样的,我们现在用的 是redis的哨兵模式集群的 有的时候由于网络等原因可能会出现脑裂的情况,就是说,由于redis master节点和redis salve节点和sentinel处于不同的网络分区,使得sentinel没 有能够心跳感知到master,所以通过选举的方式提升了一个salve为master, 这样就存在了两个master,就像大脑分裂了一样,
这样会导致客户端还在 old master那里写入数据,新节点无法同步数据,当网络恢复后,sentinel会 将old master降为salve,这时再从新master同步数据,这会导致old master中 的大量数据丢失。
关于解决的话,我记得在redis的配置中可以设置:第一可以设置最少的salve 节点个数,比如设置至少要有一个从节点才能同步数据,第二个可以设置主 从数据复制和同步的延迟时间,达不到要求就拒绝请求,就可以避免大量的数据丢失
分片集群
主从和哨兵可以分别解决高并发读和高可用的问题。但是依然有两个问题没有解决:
海量数据存储问题
高并发写的问题
使用分片集群可以解决上述问题,
分片集群特征:
节点间不是主从关系,集群中有多个master,每个master保存不同数据(解决高并发写)
每个master都可以有多个slave节点(解决高并发读)
master之间互相通过ping心跳监测彼此健康状态(解决高可用)
客户端请求可以访问集群任意节点,最终都会被转发到正确节点(完成了哨兵的通知功能)
分片集群结构-数据读写
Redis 分片集群引入了哈希槽的概念,Redis 集群有 16384 个哈希槽,每个 key通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。
同时也可以按照一定的规则来选择存储到哪一个节点,如图右,{ }中的就是有效部分,如果有相同的业务数据,想要存储到同一个节点中,就可以设置相同的有效部分进行存储数据,如果没有设置,就会通过key来计算
面试回答
面试官:redis的分片集群有什么作用
候选人:分片集群主要解决的是,海量数据存储的问题,集群中有多个 master,每个master保存不同数据,并且还可以给每个master设置多个slave 节点,就可以继续增大集群的高并发能力。
同时每个master之间通过ping监 测彼此健康状态,就类似于哨兵模式了。当客户端请求可以访问集群任意节 点,最终都会被转发到正确节点
面试官:Redis分片集群中数据是怎么存储和读取的?
候选人: 在redis集群中是这样的 Redis 集群引入了哈希槽的概念,有 16384 个哈希槽,集群中每个主节点绑 定了一定范围的哈希槽范围, key通过 CRC16 校验后对 16384 取模来决定放 置哪个槽,通过槽找到对应的节点进行存储。 取值的逻辑是一样的