redis 主从复制

redis的持久化RDB与AOF详解文章中,我们知道如果redis宕机了,我们可以通过AOF 和 RDB 文件的方式恢复数据,从而保证数据的丢失(或少量损失)从而提高稳定性。但是,如果我们数据只存在一台redis服务器中,那么在恢复期间我们无法提供服务的,这不符合服务器的高可靠性。如果更加严重的话,这台服务器的硬盘出现了故障,那么数据是不是全部丢失了吗?这也是无法接受的。

那么为了避免这种单点故障,我们有什么办法呢?有同学可以会想到MYSQL 主从复制的机制。那就恭喜你了,你想的答案是对的。在redis中也提供主从复制模式来解决这样的问题。

在redis主从复制模式下,为了保证多台服务器的数据一致性,主从库采用读写分离的方式:

1. 从库和主库都可以接受读操作;

2. 对于写操作,首先要到主库执行,然后主库再将写操作同步到从库;

 有人可能会问为什么要使用读写分离的方式呢?其实答案很简单,如下:

1. 只有主库接收写操作可以避免客户端将数据修改到不同的redis实例中,当然了这样其他客户端读取数据时有可能读到旧值

2. 如果非要所有的库都可以进行写操作,就要涉及到锁、实例间协商是否完成修改等一系列操作,会带来额外的开销

在redis主从复制是怎么进行的呢?

redis主从复制

redis主从复制的过程:

1. 主从库建立连接、协商同步的过程

2. 主服务器同步数据给从服务器

3. 主服务器发送新写操作命令给从服务器

这三个过程如下图:

redis主从复制的过程

主从库建立连接、协商同步的过程

在从库中执行下面命令:

replicaof <主库的 IP 地址> <主库 的 Redis 端口号>

然后从库就会向主库发送psync 命令,不是要进行数据同步。

psync 命令两个参数(主库的 runID 和复制进度 offset)解析:

1. runID :每个 Redis 服务器在启动时都会自动生产一个随机的 ID 来唯一标识自己。当从服务器和主服务器第一次同步时,因为不知道主服务器的 run ID,所以将其设置为 "?"

2. offset:表示复制的进度,第一次同步时,其值为 -1

主服务器收到 psync 命令后,会用 FULLRESYNC 作为响应命令返回给对方,包含两个参数:主库 runID 和复制进度 offset。从服务器收到响应后,会记录这两个值。

其中 FULLRESYNC 代表的全量复制,会将主库所有的数据都复制给从库。

这就是第一个阶段,它是为了全量复制做准备。

主服务器同步数据给从服务器

在第一个阶段完成之后,主服务器会执行 bgsave 命令来生成 RDB 文件,然后把文件发送给从服务器。从库接收到 RDB 文件后,首先清空当前数据,然后再加载 RDB 文件。

这个过程主库不会被阻塞,仍然可以接受请求,如果存在写操作,刚刚生成的 RDB 文件中是不包含这些新数据的,此时主库会在内存中用专门的 replication buffer 记录 RDB 文件生成后所有的写操作

主服务器发送新写操作命令给从服务器

主库会把 replication buffer 中的修改操作发给从库,从库重新执行这些操作。至此,主从服务器的第一次同步的工作就完成了。

在第一次同步完成之后,主从就会一直维护一个 TCP 连接。这时候,如果主库有写操作过来,也会将写操作命令传播给从库。这样就保证了主从数据数据的一致性。

分摊主服务器的压力

如果从库的实例过多,对于主库来说有一定的压力,主库会频繁 fork 子进程以生成 RDB 文件,fork 这个操作会阻塞主线程处理正常请求,导致响应变慢,Redis 采用了主-从-从的模式,可以手动选择一个从库,用来同步其他从库的数据,以减少主库生成 RDB 文件和传输 RDB 文件的压力;如下图:

级联的“主-从-从”模式

这样从库就可以知道在进行数据同步的时候,不需要和主库直接交互,只需要和选择的从库进行写操作同步就可以了,从而减少主库的压力。

增量复制

从前面我们知道主从复制在完成第一次同步后,就会基于长连接进行命令传播。但是,在这个长连接中有可能会出现断网等各种不好的情况。这个时候,在从库读取的数据是旧数据。当断网重新恢复回来时,那么主从怎么保证数据的一致性的呢?

主从会采用增量复制的方式把网络断开期间主服务器接收到的写操作命令,同步给从服务器。

网络恢复后的增量复制过程如下图:

增量复制过程

 图解析如下:

1. 从服务器在恢复网络后,会发送 psync 命令给主服务器,此时的 psync 命令里的 offset 参数不是 -1

2. 主服务器收到该命令后,然后用 CONTINUE 响应命令告诉从服务器接下来采用增量复制的方式同步数据

3. 然后主服务将主从服务器断线期间,所执行的写命令发送给从服务器,然后从服务器执行这些命令

主库是怎么存放断线期间所执行的写命令的呢?

主要是使用repl_backlog_buffer和replication offset来实现的

repl_backlog_buffer:是一个「环形」缓冲区,用于主从服务器断连后,从中找到差异的数据

replication offset:标记上面那个缓冲区的同步进度,主从服务器都有各自的偏移量,主服务器使用 master_repl_offset 来记录自己「」到的位置,从服务器使用 slave_repl_offset 来记录自己「」到的位置

在主服务器进行命令传播时,不仅会将写命令发送给从服务器,还会将写命令写入到 repl_backlog_buffer 缓冲区里,因此 这个缓冲区里会保存着最近传播的写命令。

网络断开后,当从服务器重新连上主服务器时,从服务器会通过 psync 命令将自己的复制偏移量 slave_repl_offset 发送给主服务器,主服务器根据自己的 master_repl_offset 和 slave_repl_offset 之间的差距,然后来决定对从服务器执行哪种同步操作:

  • 如果判断出从服务器要读取的数据还在 repl_backlog_buffer 缓冲区里,那么主服务器将采用增量同步的方式;

  • 相反,如果判断出从服务器要读取的数据已经不存在 
    repl_backlog_buffer 缓冲区里,那么主服务器将采用全量同步的方式

当主服务器在 repl_backlog_buffer 中找到主从服务器差异(增量)的数据后,就会将增量的数据写入到 replication buffer 缓冲区,这个缓冲区我们前面也提到过,它是缓存将要传播给从服务器的命令。

repl_backlog_buffer 最小配置可以通过repl-backlog-size来设置。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yi Ian

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值