Redis高可用中的复制是怎样实现的?

Redis经过不断发展,现在已经作为一款非常优秀的分布式缓存数据库,高性能是它出生便携带的强悍特点,但是要作为分布式服务,一如优秀的它,也必然少不了负载均衡、高可用等等的特性实现。下面主要谈下Redis的复制功能实现。

复制(replicate)

“高可用性”(High Availability)通常来描述一个系统经过专门的设计,从而减少停工时间,而保持其服务的高度可用性。既然要保持其服务的高度可用性,就是容忍突发情况对服务实例灾难性的摧毁。对于使用单机的Redis,万一运行这个Redis实例的机器挂了或者机器网络原因导致访问不了,我们依赖到Redis的服务的应用也将不可用。如果想实现高可用,重要方式就是备份,Redis的主从模式就是如此,从服务复制主服务的数据,一旦主服务器挂了,从服务器可以平滑的替换主服务器,能够无缝地替换的前提就是复制,复制使主从服务器保存相同的数据。复制我认为是Redis实现高可用的基石。

体验复制功能的使用过程

体验复制功能的过程其实很简单,首先安装完Redis,用户可以启动两个不同端口的实例,然后通过salveof命令设置slaveof配置选项,让一个服务器去复制另一个服务器。

  1. 分别启动7001、7002端口的Redis服务器实例
redis-server --port 7001
redis-server --port 7002
  1. 连接7001端口Redis,发送slaveof 127.0.0.1 7002命令

连接:

redis-cli -p 7001
slaveof 127.0.0.1 7002

这样,就完成7001端口Redis成为7002端口Redis从服务器的设置,然后通过在主服务器执行set number 12345命令,看看从服务器是否能顺利获取number的值

  1. 主服务执行set number 12345,从服务器执行get number命令
    在这里插入图片描述
    在这里插入图片描述
    从执行效果来看,可以得出7001端口从服务器能顺利从7002端口主服务器复制数据的结论。

一、旧版复制功能的实现

Redis的复制功能分为同步(sync)和命令传播(command),随着Redis版本发展,复制功能的实现分为了旧版(2.8版本以前)的实现,新版(2.8版本之后)实现。

Redis的复制功能分为同步(sync)和命令传播(command propagate)两个操作:

  1. 同步操作用于将从服务器的数据库状态更新至主服务器当前所在的数据库状态。
  2. 命令传播操作,字面的意思就是主服务器把对数据库状态造成影响的写命令传播到从服务器,让从服务器始终和主服务器数据库状态保持一致

1.1 同步

进行同步的操作很简单,就是往从服务器发送slaveof命令,命令从服务器作为某个服务器的slave,比如上面就展示了,连接7001端口Redis,发送slaveof 127.0.0.1 7002命令过程和效果。
对从服务器发送slaveof命令后,从服务器对主服务器的同步操作是通过发送sync命令来完成的,以下是sync命令的执行步骤。

  1. 从服务向主服务器发送sync命令。
  2. 收到sync命令的主服务器执行bgsave命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令。
  3. 当主服务的bgsave命令执行完毕时,主服务器会将bgsave命令生成的RDB文件发送给从服务器,从服务器接受并载入这个RDB文件,将自己的数据库状态更新至服务器执行bgsave时的数据库状态。
  4. 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务执行这些写命令,将数据库状态同步更新到和主服务一样的数据库状态。

1.2 命令传播

在同步操作执行完后,主从服务器数据库在这个时候达成了暂时的一致性,为什么说暂时呢?毕竟主服务器还会持续的执行写命令,这些写命令产生的数据变化,是通过命令传播方式同步给从服务器的。
但是旧版命令传播功能在断线后,然后重新连接复制上会存在一个很大的问题,看下面的断线重复制过程。
在这里插入图片描述
从上图可以看到,在T10091主从服务器断线,重新连接,T10092从服务器会发送SYNC命令,主服务器在T10093时候会再走一次同步复制的老路,不是从T10090执行的SET k10089 v10089命令开始重新传播,而是从刚开始执行命令传播的set k1 v1命令开始。如果在主从服务器断线期间,主服务器执行的写命令成千上万的,这就很低效要命了。这种低效的感觉,类似于我们平常下载一个2g的电影,下载到99%,突然网络断线失败要重新下载的无力感。当然网络下载得益于断点上传和断点下载的支持,不再存在我说的因网络断线要重新下载的情况了。那么类比下下载,Redis在传播命令上能否也能实现和断点上传的效果呢?答案肯定是能的。

二、新版复制功能的实现

从上面介绍可以了解到旧版复制功能在处理断线重复制情况时存在低效问题,Redis从2.8版本开始,使用PSYNC命令代替SYNC命令来执行复制时的同步操作,从而解决了旧版复制功能的低效问题。其实稍加思考下,解决这个问题的思路很简单,我们下载东西的时候常常会看到下载过程中显示的进度条,如果在同步完成后进行命令传播阶段,主从服务器能够双方维护一个此刻进度的偏移量(位置),如果断线,就可以根据这个偏移量开始继续传命令,则不必从头开始了。具体实现看下面。

2.1 PSYNC命令

PSYNC命令具有完整重同步(full resynchronization)和部分重同步(partial resynchronization)两种模式:

  • 完整重同步和SYNC命令的执行步骤基本一样,它们都是通过让主服务器创建并发送RDB文件,以及向从服务器发送保存在缓冲区里面的写命令来进行同步。
  • 部分重同步则用于处理断线后重复制情况,当从服务器在断线后重新连接主服务器时,如果条件允许,主服务器将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态。
    PSYNC命令的部分重同步模式很好的解决了旧版复制功能在处理断线后重复制时出现的低效情况,下图展示了,PSYNC命令的解决过程
    在这里插入图片描述
    我们可以看到在PSYNC模式,主从服务器断线重连后,从服务器会向主服务器发送PSYNC命令,主服务器会向从服务器返回+CONTINUE回复,表示执行部分重同步,然后从服务器接收+CONUTINUE回复,准备执行部分重同步…
    关键过程还是在于T10092 到 T10094的实现细节。

2.2 部分重同步实现细节

部分重同步功能由以下三个部分构成:

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

我们其实可以尝试根据这三个部分脑补下部分重同步的实现,怎样能在断线恢复后,从断线前一刻执行的命令开始继续进行命令传播呢?这个很简单,在主服务器每次命令传播时,主从服务器都维护下复制的偏移量就好,主服务器每次传播N个字节数据,就将自己的复制偏移量的值加上N,从服务器接收到N个字节时,就将自己的复制量加上N。当断线重连时候,就能在断线前的复制偏移量开始传播命令,但是断线到重连后这个时间段主服务执行的写命令咋办?主服务器搞一个复制积压缓冲区把断线期间执行的命令存起来就好啦,当执行部分重同步时,主服务器根据从服务器重连自己后发来的复制偏移量,对比自己维护的复制偏移量,可以继续传播断线期间,从服务器没有接受到的在主服务的执行命令。说到这里,貌似有了复制偏移量和复制积压缓存区就可以实现了,服务器运行ID有什么用?每个Redis服务器都有一个运行ID,运行ID是在服务器启动时候产生的,由40个16进制字符组成,当从服务器对主服务器进行初次复制时,主服务器会将自己的运行ID传送给从服务器,从服务器会将这个运行ID保存下来,当从服务器断线重新连接上主服务器时候,从服务会把这个运行ID传给主服务器,主服务接受到这个运行ID,会判断下是不是自己的运行ID,如果是,说明是断线重复制场景,否则就是完整重同步场景,而进行相应的处理。

后记

到此为止,Redis的复制功能原理就介绍到这里了,复制是Redis实现高可用的基石,具有非常重要的意义。Redis从单机版慢慢演进到支持高可用、集群横向扩展,实在是很优秀的一款中间件。另外从复制功能可以看到,Redis有些功能并不是一开始就设计很完美的,都是不断完善改进的,数据结构的设计。学习Redis不单单是对工作使用上有帮助,它的不断演进优化设计思想也对我们有很大的启发。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值