Redis主从复制

Redis主从复制

简介

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);

数据的复制是单向的,只能由主节点到从节点。

  • 为了要避免单点故障后,数据库依旧能正常使用,即保证高可用,便需要多结点方式提供集群服务。
  • 而Redis 提供了主从库模式,以保证数据副本的一致,主从库之间采用的是读写分离的方式。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5R1kKzuy-1651559571676)(Redis.assets/image-20220503143012378.png)]

作用

主从复制的作用主要包括:

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

读写分离

主从库之间采用的是读写分离的方式。

  • 读操作:主库、从库都可以接收;

建立主从关系

例如,现在有实例 1(ip:172.16.19.3)和实例 2(ip:172.16.19.5),我们在实例 2 上执行以下这个命令后,实例 2 就变成了实例 1 的从库,并从实例 1 上复制数据:

replicaof 172.16.19.3 6379

传播命令

区分repl__buffer 和 repl_backlog_buffer

当主服务器进行命令传播的时候,maser不仅将所有的数据更新命令发送到所有slave的replication buffer,还会写入replication backlog

  • 一个replication buffer对应于一个slave
  • replication backlog buffer 是一个环形缓冲区,整个master进程中只会存在一个,所有的slave公用。

主从复制原理

注意:在2.8版本之前只有全量复制,而2.8版本后有全量和增量复制:

  • 全量(同步)复制:用于初次复制其它无法进行部分复制的情况,将主节点中的所有数据都发送给从节点。当数据量过大的时候,会造成很大的网络开销。
  • 增量(同步)复制:**只会把主从库网络断连期间主库收到写的命令,同步给从库。**补发的数据远远小于全量数据,可以有效避免全量复制的过高开销。

主节点运行ID(runId

是每个 Redis 节点启动时都会自动生成的一个随机 ID

  • 需要注意的是redis关闭再启动,运行的id会随之变化

  • 当从库和主库第一次复制时,因为不知道主库的 runID,所以将 runID 设为“?”。offset,此时设为 -1,表示第一次复制

复制偏移量(offset)

img

主节点和从节点都各自维护自己的主从复制偏移量offset,当主节点有写入命令时,offset=offset+命令的字节长度。从节点在收到主节点发送的命令后,也会增加自己的offset,并把自己的offset发送给主节点。这样,主节点同时保存自己的offset和从节点的offset,通过对比offset来判断主从节点数据是否一致。

复制积压缓冲区(repl_backlog_buf)

在2.8版本,redis使用了新的复制方式,引入了复制积压缓冲(replication backlog)

在这里插入图片描述
  • 复制积压缓冲区是保存在主节点上的一个固定长度的队列,默认大小为1MB,当主节点有连接的从节点时被创建,这时主节点响应写命令时,不但会把命令发给从节点,还会写入复制积压缓冲区
  • 除了存储写命令,还存储了写命令的每个字节对应的复制偏移量(offset) 。由于复制积压缓冲区定长且先进先出,所以它保存的是主节点最近执行的写命令;时间较早的写命令会被挤出缓冲区。

全量复制

形成主库和从库的关系,之后会按照三个阶段完成数据的第一次同步

全量复制的三个阶段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i5Gs8N3J-1651559571678)(Redis.assets/image-20220503143039567.png)]

第一阶段是主从库间建立连接、协商同步的过程

主要是为全量复制做准备。在这一步,从库和主库建立起连接,并告诉主库即将进行同步,主库确认回复后,主从库间就可以开始同步了。

具体来说,从库给主库发送 psync 命令,表示要进行数据同步,主库根据这个命令的参数来启动复制。psync 命令包含了主库的 runID 和复制进度 offset 两个参数。主库收到 psync 命令后,会用 FULLRESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset,返回给从库。从库收到响应后,会记录下这两个参数。这里有个地方需要注意,FULLRESYNC 响应表示第一次复制采用的全量复制,也就是说,主库会把当前所有的数据都复制给从库

第二阶段,主库将所有数据同步给从库

从库收到数据后,在本地完成数据加载。这个过程**依赖于内存快照生成的 RDB 文件。**

  1. 主库执行 bgsave 命令,生成 RDB 文件,接着将文件发给从库
  2. 从库接收到 RDB 文件后,会先清空当前数据库,然后加载 RDB 文件
  3. 在主库将数据同步给从库的过程中,主库不会被阻塞,仍然可以正常接收请求。否则,Redis 的服务就被中断了。
  4. 为了保证主从库的数据一致性,主库会在内存中用专门的 replication buffer,记录 RDB 文件生成后收到的所有写操作。

第三个阶段,主库会把第二阶段执行过程中新收到的写命令,再发送给从库

具体的操作是,当主库完成 RDB 文件发送后,就会把此时 replication buffer 中的修改操作发给从库,从库再重新执行,最终实现主从库同步


增量复制

Redis 2.8 版本引入了增量复制,从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步。

为什么会设计增量复制

如果主从库在命令传播时出现了网络闪断,那么,从库就会和主库重新进行一次全量复制,开销非常大

增量复制的流程

你可以先看一下下面这张图,有个整体感知,接下来我再具体介绍。

在这里插入图片描述

  1. 如果网络抖动(连接断开 connection lost)

  2. 主机master 还是会写 replbackbuffer(复制缓冲区)

  3. 从机slave 会继续尝试连接主机

  4. 从机slave 会把自己当前 runid 和偏移量传输给主机 master,并且执行 pysnc 命令同步

  5. 如果 master 发现你的偏移量是在缓冲区的范围内,就会返回 continue 命令,表示可以增量复制

  6. 根据offset把复制积压缓冲区里的数据发送给从节点,所以部分复制的基础就是偏移量 offset

如果在网络断开后,判断进行全量复制还是增量复制

在和主库重连进行恢复时,从库会通过psync命令把自己记录的slave_repl_offset发给主库,从节点将offset发送给主节点后,主节点根据offset和缓冲区大小决定能否执行部分复制

如果主库repl_backlog_buffer的从节点偏移量offset位置上的数据已经被覆盖掉了,就需要进行全量复制

深入理解

为什么主从全量复制使用RDB而不使用AOF?

  • 内存占用小:RDB是经过压缩的二进制数据,而AOF文件记录的是每一次写操作的命令,写操作越多文件会变得很大,其中还包括很多对同一个key的多次冗余操作。
  • 速度快:从库直接按照RDB协议解析还原数据即可,速度会非常快,而AOF需要依次执行每个写命令,恢复速度相比RDB会慢得多,

为什么还会有从库的从库的设计?

通过分析主从库间第一次数据同步的过程,你可以看到,一次全量复制中,对于主库来说,需要完成两个耗时的操作:生成 RDB 文件和传输 RDB 文件

  • 从库数量多,主库会fork操作频繁,阻塞主线程
  • 传输 RDB 文件也会占用主库的网络带宽

从库数量多,主库的压力会很大

可以使用**“主 - 从 - 从”模式** 将主库生成 RDB 和传输 RDB 的压力,以级联的方式分散到从库上

简单来说,我们在部署主从集群的时候,可以手动选择一个从库(比如选择内存资源配置较高的从库),用于级联其他的从库。然后再选择一些从库(例如三分之一的从库),让它们和刚才所选的从库,建立起主从关系。

replicaof 所选从库的IP 6379

这三分之一的从库就不用再和主库进行交互了,只要和级联的从库进行写操作同步就行了,这就可以减轻主库上的压力,如下图所示:
在这里插入图片描述

读写分离及其中的问题

在主从复制基础上实现的读写分离,可以实现Redis的读负载均衡:由主节点提供写服务,由一个或多个从节点提供读服务;在读负载较大的应用场景下,可以大大提高Redis服务器的并发量。

下面介绍在使用Redis读写分离时,需要注意的问题。

延迟与不一致问题

由于主从复制的命令传播是异步的,延迟与数据的不一致不可避免。

  • 优化主从节点之间的网络环境(如在同机房部署);
  • 监控主从节点延迟(通过offset)判断,如果从节点延迟过大,通知应用不再通过该从节点读取数据;
  • 使用集群同时扩展写负载和读负载等。
数据过期问题

在主从复制场景下,为了数据一致性,从节点不会主动删除数据,而是由主节点控制从节点中过期数据的删除。但是由于主节点的删除策略,对过期数据执行删除操作,从节点很容易读取到已经过期的数据。

在单机版Redis中,存在两种删除策略:

  • 惰性删除:服务器不会主动删除数据,只有当客户端查询某个数据时,服务器判断该数据是否过期,如果过期则删除。(和超市一样,顾客买到过期的才换)
  • 定期删除:服务器执行定时任务删除过期数据,但是考虑到内存和CPU的折中(删除会释放内存,但是频繁的删除操作对CPU不友好),该删除的频率和执行时间都受到了限制。

Redis 3.2中,从节点在读取数据时,增加了对数据是否过期的判断:如果该数据已过期,则不返回给客户端;将Redis升级到3.2可以解决数据过期问题。

故障切换问题

没有使用哨兵的读写分离场景下,当主节点或从节点出现问题而发生更改时,需要及时修改应用程序读写Redis数据的连接,成本都不算低

  • 连接的切换可以手动进行,响应慢、容易出错,或者
  • 自己写监控程序进行切换,实现复杂
总结

在使用读写分离之前,可以考虑其他方法增加Redis的读负载能力:

  • 如尽量优化主节点(减少慢查询、减少持久化等其他情况带来的阻塞等)提高负载能力;
  • 使用Redis集群同时提高读负载能力和写负载能力等。
  • 如果使用读写分离,可以使用哨兵,使主从节点的故障切换尽可能自动化,并减少对应用程序的侵入。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值