初学Redis之Redis主从库模式

AOF日志和RDB内存快照两块内容只是保证了Redis数据的可靠性。但还是存在数据丢失的风险,若Redis宕机的期间,有操作命令到了客户端,此时这些数据并没有记录到日志或者在rdb快照中。

Redis的高可靠性

主要有两点:数据少丢失连接少断开

AOF日志和RDB内存快照是确保了数据的准确性,主从库模式则是确保了连接的稳定性。

而主从库顾名思义就是有主库和从库,需要将从库与主库进行连接,连接后从库就会从主库中复制数据,主库若有新增数据也会增量的同步到从库中。

方法1:有两个redis实例,redis1(168.172.3.4)和redis2(168.172.3.5),那么可以设置redis2是redis1的从库。在redis2实例中输入命令replicate(在Redis 5.0之前使用的是slaveof):

replicaof 168.172.3.4 6379

这样就形成了主从关系,Redis2实例是redis1实例的从库。
方法2:
1.将redis所在的文件夹复制多份,修改文件夹名称。
2.修改文件夹的redis.windows.conf文件内的port端口,不与主库一致就行。并修改slaveof进行主从连接。
3.将新增的redis实例设置新的服务。
以下为图片:

在这里插入图片描述
以6380为例:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
然后在cmd中输入redis-server --service-install redis.windows.conf --loglevel verbose --service-name redis6380命令生成redis服务
启动主库服务,再启动从库服务即可自动连接主库。
而客户端可以选择要连接的服务端redis-cli -h 127.0.0.1 -p 6380即可连接6380服务端。

主从库之间,是怎样同步数据的?
流程图如下:
在这里插入图片描述
第一阶段:从库与主库创建连接,并通知主库,等待确认后,向主库发送命令psync,带有参数主库runid以及offset。runid:是主库随意生成的唯一实例id,由于是第一次连接,还不知道主库的runid所以为"?",offset: 为-1指的是第一次同步。然后主库中返回FULLRESYNC[RUNID][OFFSET]命令,表示第一次为全量同步,同时从库记录runid以及offset。

第二阶段:由主库bgsave生成一个rdb文件,传输给从库,从库接收到rdb文件后,将从库的数据都删除(防止数据错误),再执行rdb。

第三阶段:再将传输rdb文件过程中新到的命令传输给从库。具体就是在rdb传输后,将replication buffer里的修改数据再次传给从库。
这样一来,主从库的同步就实现了。

主从库同步主要有两个地方有开销:

  1. 主库生成rdb文件(需要fock子进程,会影响主线程。)
  2. 传输rdb文件(会占用主库的带宽)

如若从库的数量过多的话,那么每个从库都会请求与主库进行数据交互,就势必会造成主库不断的fock子进程生成RDB,我们知道fock的时候会是主库的线程阻塞,影响主库的使用。同时传输rdb文件的时候也会增加主库的网络带宽,这就影响了主库应用程序的响应速度。

那有什么方法能分担主库的压力呢?
有,那就是 “主-从-从”模式

主从级联模式分担主库压力

使用“主-从-从”模式让从库帮主库分担生成RDB文件和传输RDB文件的压力。
当部署主从集群的时候,我们可以为某个从库手动选择主库:

replicaof 从库ip 6379

这样从库就知道不需要去和主库进行数据的交互了,帮主库分担了压力。一旦主从库形成了链接,就会一直保持,主库就会通过这个链接将后续新的数据传递到从库中,这就是基于长链接的命令传播
下面画一个主-从-从模式的图:
在这里插入图片描述
要是主从间的网络链接断了怎么办?
在redis2.8之前,网络连接突然闪断后,从库就会与主库进行一次全量同步,若数据量庞大,那开销就会很大。
在redis2.8之后,网络断开后,会使用增量复制的方法继续同步,将断连期间新增的数据同步到从库中。

具体操作是,在断连期间,若有新的数据进入主库,会将数据保存到replication buffer,并把数据同步到缓冲区repl_backlog_buffer内。

repl_backlog_buffer是一个扇形缓冲区,主库记录的是自己写到的位置,从库记录的是自己读到的位置。 若主库在断连期间有N条数据进来,那么就有偏移量master_repl_offset,在主从链接上后,从库就将自己读到的位置slave_repl_offset发送给主库,主库就自行判断取得master_repl_offset——slave_repl_offset之间的数据传输给从库。

一开始主库与从库都在一个起始位置,当主库有数据读入的时候,master_repl_offset偏移量就产生,主从连接上后,slave_repl_offset偏移量也跟着产生,正常来说master_repl_offset与slave_repl_offset是一致的。

这里要注意的是,由于repl_backlog_buffer是扇形缓冲区,那么如果主从迟迟没有连接上,导致从库的偏移量始终追不上主库,那么主库新的数据就会将扇形缓冲区的数据覆盖,就会导致数据丢失。
解决这个方法可以配置repl_backlog_size的大小,来将缓冲区设置的较大,不让新的数据覆盖掉还未同步的数据。

如果主库挂了,如何不间断服务?

如果主库挂了,这时就需要有 “哨兵机制” 来对主从库进行:监听、换主、通知 这三个过程。

动作作用
监听监听主库、从库是否与客户端断连。
换主若主库客观下线则,从从库中选择一个成为主库
通知更换主库后,需要通知从库新主库的ip,使从库与新主库连接,并通知客户端。

监听:监听主库是否下线
哨兵会使用ping与主库和从库进行交互,若ping不通,则判断主库主观下线。但是这可能只是哨兵觉得主库下线了,但是实际上并没有下线。可能是因为主库与哨兵之间网络连接不好,或者此时主库较为拥塞。若这时就判定主库下线,那么就可能会形成不必要的开销。

若要处理这点,就需要配置3个哨兵,由3个哨兵去监听主从库,若有3/2+1以上的哨兵设置主库主观下线,那么就可以判定主库客观下线,从而进行主从库切换。

换主:主库下线后,从从库中选择一个成为新主库
换主的过程有三个筛选过程:

  1. 筛选掉已经下线的从库
  2. 从剩下的从库中选择网络连接较好的从库
  3. 首先根据优先级筛选(可以通过配置slave_priority),若没有优先结果;再次根据从库与旧主库之间数据是否接近(使用master_repl_offset与slave_repl_offset是否接近),若都接近;最后根据从库的ID,ID最小,就选定该从库为新主库。

通知:通知从库新主库ip,通知redis新主库
这其实涉及到了哨兵集群,哨兵集群就是有多个哨兵共同来监控。

要怎么建立集群?

可以通过redis的PUB\SUB订阅机制,每一个哨兵将自己的ip和端口号发布到同一个频道中,然后都订阅这个频道,此时每个哨兵都知道其他哨兵的ip与端口号,就可以建立起网络连接,此时就形成了哨兵集群。

leader哨兵切换完新主库后,也是通过PUB发布新主库ip,然后其他从库订阅频道,获取新主库ip进行主从库配置。

那要怎么通知到redis呢?
其实哨兵就是一个运行在特定条件下的redis实例,同样它们有自己的PUB\SUB订阅机制,也有自己的一些事件。redis客户端只需要订阅哨兵发布的事件,就可以通知到redis了。

哨兵的订阅有很多事件,主要的时间有:主库下线判断、新主库选定、从库重新配置。

在这里插入图片描述
这样我们就可以在客户端中订阅哨兵的消息了

订阅“所有实例客观下线的事件状态”

SUBSCRIBE +odown

也可以订阅所有事件

SUBSCRIBE *

最后我们来看看如何添加哨兵?

sentinel monitor [mater_name] [ip] [redis_port] [quorum]

可以通过上述命令语句添加哨兵,对应参数有:
master_name : 主库名
ip : 哨兵实例ip
redis_port : 6379
quorum : 通过quorum判断客观下线以及竞选leader

如果哨兵挂掉了,还能进行主从库切换吗?
若有一个哨兵挂掉了,还有其他的哨兵实例存在,只要剩余哨兵实例的个数大于配置哨兵时设置的quorum值,那就可以进行主从库切换。若有四个哨兵,挂了一个,那若需要选举一个leader来进行主从库切换就必须有3个以上哨兵同意,但是此时只有三个哨兵,3/2+1=2所以此时并不能进行主从库切换。

那就多配置几个哨兵,每个哨兵之间建立网络连接,形成哨兵集群,并且每个哨兵都与主库从库以及redis客户端都保持通信。

哨兵要怎么获取到从库的信息?
哨兵通过向主库发送INFO命令,主库响应后,返回从库列表,然后哨兵就根据从库列表的连接信息来与从库进行连接。

在这里插入图片描述

那要如何进行主从切换?

首先就要判断主库为客观下线,这个过程就是每个实例自身判断主库为主观下线,都向其他哨兵发送is-master-down-by-addr标识,返回N或Y。

一个哨兵获得仲裁赞成票超过quorum值后,就将主库标记为客观下线。此时该哨兵自己想要当leader,就提起leader仲裁。仲裁赞成票超过quorum值,就竞选成为leader,进行主从库切换。

时刻S1S2S3
T1S1想要成为leader,给自己投一票赞成,将请求发送给其他哨兵
T2S3收到S1的请求,但是自己也想要成为leader,所以给S1投反对票(N),给自己投了赞成票
T3S2先收到了S1的请求,给S1投了赞成票,此时S1有两票
T4这时S2才收到了S3的请求,但是已经给S1投了赞成票,所以只能给S3投反对票

此时的结果就是,哨兵1获得2票,哨兵3获得1票,3/2+1=2,所以哨兵1就成为了leader,进行主从切换的操作。
为什么S2会先接受到S1的请求?这个就可能是应为S3和S2之间的网络连接正在拥塞,和S1的网络连接较好,先接收到了S1的请求。

此时,主从库切换的过程就完成了。

如何通知从库以及redis客户端新主库的信息?
这就是使用redis客户端的PUB\SUB发布\订阅机制以及哨兵本身的PUB\SUB订阅机制。
前一种与哨兵之间数据交互;redis客户端从哨兵的发布\订阅机制获取新主库信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值