Redis主从复制及其实现原理

Redis主从复制及其实现原理

首先,简单介绍一下什么是Redis主从复制

假如我们服务中用到了Redis,并且只有一台Redis服务器。如果某个时刻该Redis服务挂了,那么会导致整个服务的Redis不可用,在此期间,大量的请求将会直接打到数据库(mysql),导致数据库压力陡增,严重的可能导致数据库直接挂掉。这种情况,我们称之为单点故障

为了应对Redis的单点故障问题,于是就有了Redis的主从复制,也就是服务中存在多台Redis服务器,或者称之为Redis节点。所有Redis节点的数据都是一样的,其中一个Redis节点作为主节点(主库),其余的Redis节点作为该节点的从节点(从库)。这就是Redis提供的主从模式

然后主从模式下采用读写分离

  • 读操作:主库从库均可执行读操作,主要从从库读。
  • 写操作:仅主库可以执行写操作,然后把数据同步给各个从库,保证主从数据一致性。
    redis主从复制

通过上面的介绍,相信大家应该了解了什么是Redis的主从复制。

那么,如何实现Redis的主从复制功能呢?
因为Redis提供了主从模式的功能,所以我们只需要在Redis节点的配置文件(redis.conf)配置相关项即可。

  • 主节点无需做任何修改
  • 从节点需要修改 redis.conf 配置文件的相关配置,如下:
# 配置主节点的ip和端口 注意:Redis5.0之后 slaveof 改成了replicaof
slaveof 127.0.0.1 6379
# 是否只读 redis2.6及之后 从节点默认只读
slave-read-only yes
# 主节点登录密码(如果主节点没有登录密码,则无需配置此选项)
masterauth xxxxxx

从节点配置好以上信息之后,先启动主节点,再启动从节点,主从节点便会建立联系,开始执行主从同步操作。
那么,这个主从同步流程具体是如何执行的呢?咱们且接着往下看。

首先,我们看一下整体的流程图,之后再逐步介绍都干了什么:
redis主从同步执行流程

第一步:主从节点建立连接,协商数据同步,为全量复制做准备
  • 主从节点第一次建立连接的时候,会执行全量复制,即把主节点的全部数据都复制到从节点,所以称之为全量复制。
  • 通过上图第一步可以看到,从节点发送 psync ? -1 命令给主节点,表示要进行复制。
    其中?代表主节点的 runId;-1 代表复制进度 offset。
    runId:每个Redis节点启动时都会生成一个唯一的随机id,用来标识这个Redis节点。当从库第一次向主库发起复制请求时,是不知道主库的runId的,所以将runId设置为问号?
    offset:复制进度为-1表示是第一次复制。
  • 主节点收到从节点的 psync 命令后,会通过 FULLRESYNC 命令进行响应,并将自己的 runId 和当前的复制进度 offset 发送给从节点。
第二步:主节点将全部数据通过RDB文件发送给从节点
  • 第二步中,主节点会执行 bgsave 命令,生成 RDB 文件,并将 RDB 文件发送给从节点。
  • 从节点收到 RDB 文件后,会先清空自己的数据(防止主从数据不一致),然后完成 RDB 文件的数据加载。
  • 主节点给从节点同步数据的过程中,RDB 文件的生成是通过子进程完成的,主节点并不会被阻塞(fork子进程会阻塞)。在此期间主节点仍然会正常接收请求,但是这些请求中的写操作并没有记录到刚刚生成的 RDB 文件中,为了保证主从数据一致性,主节点会把 RDB 文件生成后的写操作记录到内存中的一块缓冲区,即 replication buffer
第三步:主节点将第二步执行过程中接收的写请求发送给从节点,从节点重新执行这些操作,实现主从同步。

到此,Redis的主从同步具体执行流程,我们已经比较清楚了。
值得注意的是:主从复制的过程中,Redis会 fork 子进程生成 RDB 文件,这个 fork 子进程的操作会阻塞 Redis 主线程。假如从节点非常多的时候,会导致主节点忙于 fork 子进程,进而导致主节点阻塞,这时候该怎么办呢?咱们且接着往下看:
这时候,我们可以通过“主-从-从”的模式将主节点生成和发送 RDB 文件的压力以级联的方式分散到从节点

说简单点就是:可以选择一个配置相对较高的从节点,作为其他从节点的主节点,如下图所示:
在这里插入图片描述
可以看到,从节点2和从节点3的主节点就不再设置成主节点了,而是设置成从节点1。这样便可以有效缓解主节点的多从复制压力了。

那么,除了上述问题之外,还存在其他问题吗?答案是肯定的。
主从节点建立连接之后,他们之间会一直维护着一个长连接,避免频繁建立连接的开销。但是,假如这个连接断开了会怎么样呢?

Redis2.8之前,主从节点断开重连之后会执行全量复制,显然全量复制开销过大,所以在Redis2.8之后就被淘汰了,升级成了增量复制。那么,什么是增量复制呢?

增量复制

断连重连之后,从节点不会复制所有的主节点数据,只会复制断连之后这段时间的写操作数据,这就是增量复制,顾名思义,就是只复制断连后增加的那部分数据量。

增量复制的实现依赖于一个环形缓冲区 repl_backlog_buffer只要有从节点在,这个环形缓冲区就会存在主节点会在这个环形缓冲区记录自己写到的位置,从节点会在这个环形缓冲区记录自己已经读到的位置。如下图所示:

环形缓冲区
主节点的所有写操作除了复制给从节点之外,也会在这个环形缓冲区记录一份,也就是上面说到的主节点会在这个环形缓冲区记录自己写到的位置,只有预先缓存了这些写操作,当从节点断连之后,又恢复连接然后发送 psync {runId} {offset} 命令执行主从同步。主节点才能通过 {offset} 参数在环形缓存区 repl_backlog_buffer 中找到从节点断连的位置,然后发送增量数据(offset位置到主节点写到的位置之间的数据)给从节点。

注意:假如从节点断连时的读位置 offset 已经被主节点的写位置覆盖了,那么此时便无法执行增量复制操作了,只能再执行一次全量复制了。所以,为了尽量避免断连之后的全量复制,可通过 repl_backlog_size 这个参数合理设置 repl_backlog_buffer 的大小,减少发生全量复制的概率。

计算公式:缓冲空间大小 = 主节点写入命令速度 * 操作大小 - 主从节点间网络传输命令速度 * 操作大小
为应对突发情况,可将 repl_backlog_size 设置为缓冲空间大小的2倍。
即:repl_backlog_size = 缓冲空间大小 * 2

接着上面的说,增量数据是如何发送给从节点的呢,这就用到了 replication buffer

关于 replication buffer 的介绍

  • Redis和客户端或者从节点通信,都会分配一个对应的内存缓冲,通过这个内存缓冲完成数据交互,如果连接断开,这个内存缓冲也会不复存在。
  • 当和从节点进行交互的时候,这个内存缓冲专门用于复制主节点的写操作到从节点,所以叫 replication buffer。如果从节点处理数据特别慢,那么这个replication buffer 会持续增长,可能导致OOM。
  • 这个内存缓冲的大小可通过 client-output-buffer-limit 参数限制,如果超过这个限制,主节点会强行断开这个从节点(客户端)的连接。此时复制中断,如果之后再继续发起复制请求,可能会导致恶性循环,引发复制风暴,需格外注意。

以上内容参考了极客时间Redis专栏介绍以及Kaito大神的相关说明。

到此,Redis主从复制相关介绍就结束了。
这种模式可以解决Redis的单点故障问题,提高Redis的可用性。但是缺点也是很明显的,假如主节点挂了,从节点是无法自动升级成主节点的,这个过程需要人工处理,在此期间,Redis无法对外提供写操作。此时,Redis哨兵模式就该登场了,待更新…
此外,整个Redis的主从节点数据都是一样的,也就是冗余的,会造成一定的资源浪费。此时,Redis集群模式就该登场了,详见Redis集群搭建

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值