redis分布式——主从复制


在实际生产环境中,为了避免单点故障,Redis肯定不会以单机的形式部署,而是会同时部署多个实例。Redis多机数据库的实现主要有三种方式,分别是主从复制、Sentinel和集群,本文主要会详细阐述主从复制的实现原理。


本文主要内容参考自《Redis设计与实现》

 如何使用主从复制

在Redis中,可以通过SLAVEOF命令或者设置slaveof选项,可以让一个服务器去复制另一个服务器。被复制的服务器称为主服务器(master),进行复制的服务器称为从服务器。
旧版复制功能实现
在2.8版本之前,Redis的复制主要分为**同步(sync)和命令传播(command propagate)**两个操作:

同步:将从服务器的数据库状态更新成主服务器的数据库状态。
命令传播:将作用于主服务器的写命令,传播给从服务器进行执行,从而保证主从数据库状态一致。

同步


当从服务器刚执行SLAVEOF命令时,首先做的就是同步操作,将从服务器的数据库状态更新成主服务器的数据库状态。
从服务器通过向主服务器发送SYNC命令来完成同步操作,SYNC命令的执行步骤如下:

从服务器向主服务器发送SYNC命令。
主服务器收到SYNC命令之后,开始执行BGSAVE命令生成RDB文件。在生成RDB文件期间,将写命令记录在一个缓冲区中。
主服务器发送RDB文件文件给从服务器,从服务器载入该RDB文件。
主服务器发送生成RDB文件期间的写命令给从服务器,从服务器重放这些命令。此时从服务器状态和主服务器状态一致,同步操作完成。


命令传播


在同步操作完成之后,后续主服务器执行的写命令会以命令传播的方式发送给从服务器,从而保证主从数据库状态一致。
旧版复制功能的缺陷
当初次复制时,旧版复制功能没有任何问题。但是当因为网络问题,主从服务器短暂掉线重连之后,此时依然会触发复制。虽然这种方式可以让主从数据库状态重新一致,但是性能和效率都会很低。因为重连之后的复制,仍然要执行同步操作,生成完整的RDB文件,从服务器依然要载入该RDB文件。实际上,在掉线期间,只是丢失了少量写命令,此时执行完整的复制操作,显然效率太低了。


新版复制功能实现


为了解决旧版复制功能在掉线重复制的低效问题,在2.8版本之后,Redis使用PSYNC命令代替原来的SYNC命令来执行同步操作。
PSYNC命令具有完整重同步(full resynchronization)和部分重同步(patial resynchronization)两种模式:

完整重同步:用于处理初次复制的情况。跟旧版的SYNC命令基本一致,都是让主服务器生成并发送RDB文件和在此期间的写命令给从服务器来完成同步操作的。
部分重同步:用于处理掉线后的重复制情况。当从服务器掉线后重新连接主服务器,如果条件允许,可以让主服务器只将掉线期间执行的写命令发送给从服务器,从而达到主从数据库状态重新一致。


部分重同步实现
部分重同步功能主要由以下三个部分构成:

主服务器的复制偏移量(replication offset)和从服务器的复制偏移量
主服务器的复制积压缓冲区(replication backlog)
服务器运行ID

复制偏移量


执行复制的双方-主服务器和从服务器会分别维护一个复制偏移量:

主服务器每次向从服务器传播N个字节的数据时,就会将自己的复制偏移量加N。
从服务器每次收到主服务器传播来的N个字节数据时,也会将自己的复制偏移量加N。

如果主从数据库状态一致,那么它们的复制偏移量一定是相等的,反之,则表示数据库状态不一致。因此当发生掉线重连时,主从服务器的复制偏移量一定不相等。
复制积压缓存区
复制积压缓存区是由主服务器维护的固定长度的先进先出(FIFO)队列,默认大小为1MB。当主服务器进行命令传播时,不仅会将写命令发送给所有的从服务器,还会将写命令写入复制积压缓冲区中。因此,复制积压缓冲区会保存最近传播的写命令,并且复制积压缓冲区为每个字节记录了相应的复制偏移量。
当从服务器重连之后,从服务器会通过PSYNC命令将自己的复制偏移量发送给主服务器,主服务器会根据这个偏移量来决定采用哪种同步操作。

如果offset偏移量之后的数据仍然存在复制积压缓冲区中,那么采用部分重同步。
如果offset偏移量之后的数据不在复制积压缓冲区中,那么采用完整重同步。

服务器运行ID


每个Redis服务器,不论是主服务器还是从服务器,都会有自己的运行ID。运行ID在服务器启动的时候生成,由40位随机字符组成。当从服务器进行初次复制时,会将对应的主服务器运行ID也保存下来。通过这个运行ID,就能确定重连上的主服务器是不是掉线之前的主服务器,如果是的话,则尝试之前的部分重同步,反之,则执行完整重同步。
PSYNC命令的实现
PSYNC命令调用方式有两种:

如果从服务器之前没有复制过任何主服务器,那么从服务器在开始一次新的复制时,会发送PSYNC ? -1命令,主动请求完整重同步。
如果从服务器已经复制过主服务器,那么开始一次新的复制时,会发送PSYNC <runid> <offset>命令,主服务根据runid和offset参数决定使用何时复制方式。

接收到PSYNC命令的主服务器,可能会返回以下三种结果中的一种给从服务器:

+FULLRESYNC <runid> <offset>:执行完整重同步。其中runid表示主服务器的运行ID,从服务器会将其保存下来;offset是主服务器的复制偏移量,从服务器会将其作为自己的初始偏移量。
+CONTINUE:执行部分重同步。主服务器会将缺少的那部分数据发送给从服务器。
-ERR:复制错误。表示主服务器版本低于2.8,不能识别PSYNC命令。


主从复制的不足


主从复制解决了数据备份和性能(通过读写分离)的问题,但是还是存在一些不足:

RDB 文件过大的情况下,同步非常耗时。
在一主一从或者一主多从的情况下,如果主服务器挂了,对外提供的服务就不可用了,单点问题没有得到解决。如果每次都是手动把之前的从服务器切换成主服务器,这个比较费时费力,还会造成一定时间的服务不可用。
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值