Redis的设计与实现(5):主从复制策略和优化

九、复制

通过SLAVEOF命令或配置文件中设置slaveof选项,让一个服务器去复制另一个服务器,被复制的为主服务器,对其复制的称为从服务器。

9.1旧版复制功能

Redis在2.8以前使用旧版本复制,在断线重连后的从服务器会遇上低效的情况。
Redis的复制功能分为同步命令传播俩操作:

  • 同步用于把从服务器的数据库状态更新至主服务器的数据库状态
  • 命令传播是在主服务器的数据库状态被修改时,导致主从数据库状态不一致时,让主从回到一致的过程。

同步
从服务器对主服务器的同步(下文以主从代替),需要向主服务器发送SYNC命令,具体步骤:

  1. 从服务器向主服务器发送SYNC命令。
  2. 主服务器接收并执行BGSAVE,后台生成RDB文件,并用一个缓冲区记录现在开始执行的所有写命令。
  3. BGSAVE执行完毕时,主服务器将RDB文件发给从服务器,从服务器接收并载入,更新数据库状态。
  4. 主服务器将其记录在缓冲区的所有写命令发给从服务器,从服务器执行写命令。

image.png
命令传播
主从服务器同步后,当主服务器发生写操作时,主从服务器又出现不一致,主服务器需要对从服务器进行命令传播,再次回到一致状态,具体步骤:

  1. 主服务器将写命令发送给从服务器。
  2. 从服务器接收并执行相同的写命令。

旧版复制功能缺陷:
从服务器对主服务器的复制分为两种情况:

  • 初次复制,从服务器没有复制过其他主服务器,或者主服务器发生变更。
  • 网络断线重连后复制,主从服务器因为网络原因断线重连后继续复制主服务器。

旧版复制的缺陷主要体现在断线重连上,从服务器在断线重连后,向主服务器发送SYNC命令,希望将断线期间由于写操作对主的数据库状态修改同步,但主服务器接收到SYNC命令后会重新生成RDB文件,将所有的数据库状态都写到RDB,这就造成了资源的大量浪费。SYNC命令是一个非常消耗资源的操作:

  1. 主服务器执行BGSAVE生成RDB文件会消耗CPU、内存和磁盘I/O资源
  2. 主服务器需要发送RDB,消耗网络资源
  3. 从服务器接收并载入RDB,载入期间是阻塞的无法处理命令

因此,必须是真正有必要才调用SYNC命令。

9.2新版复制功能

Redis从2.8开始使用PSYNC代替SYNC命令来执行同步操作。
PSYNC有完整重同步(full resynchronization)和部分重同步(partial resynchronization)的两种模式:

  • 完整重同步用于初次复制的情况,与SYNC命令基本一样,主服务器创建并发布RDB文件,以及向从服务器发送缓存区的命令。
  • 部分重同步用于处理断线重连后的情况,重连后,如果条件允许,返回+CONTINUE,主服务器将断线期间执行的写命令发送给从服务器,从只需接收并执行这些命令。
  • image.png

可以发现PSYNC在断线重连后执行部分重同步比SYNC生成、载入整个RDB文件的效率要高得多。

9.2.1部分重同步的实现

主要基于三个部分实现:

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

再次明确一点,这三个部分是在部分重同步的场景下定义的。
复制偏移量
主从都会维护一个复制偏移量,用来表示当前复制的位置,当主服务器向从服务器传播N个字节数据时,主服务器的复制偏移量会加N,从服务器接收到之后也会加N。可以通过偏移量判断数据库状态是否一致。但有一个问题,就是从服务器断线重连后,主从偏移量不一致,执行部分还是完整重同步,这时候就需要复制积压缓冲区来帮忙判断。

复制积压缓冲区
复制积压缓冲区由主服务器维护,是固定长度的先进先出队列,默认1M。当入队元素大于队列长度时,最先入队的元素会被弹出。主服务器在命令传播时,不仅将写命令发给从,还会将写命令入队至复制积压缓冲区。(注意与持久化时AOF重写缓冲区的区别)
image.png
复制积压缓冲区会保存最近写的命令,并为队列中的每个字节记录复制偏移量
image.png
当从服务器重连后,发送PSYNC命令并将自己的复制偏移量也发送给主服务器,主服务器拿着复制偏移量去复制积压缓冲区找,如果存在则进行部分重同步并给从服务器发送+CONTINUE回复,否则进行完整重同步。因此,正确设置复制积压缓冲区的大小就十分重要,而这通常取决于两个因素:

  • 断线重连平均时间second
  • 主服务器平均每秒产生写命令的数据量write_size_per_second

为了安全起见,一般会设置缓冲区大小为2 * second * write_size_per_second。

服务器运行ID
服务器运行ID决定断线后执行哪种同步方式,主从都有运行ID,是自动生成的40个随机十六进制字符。主从第一次复制时,从服务器会保存主服务器的ID,断线后也会向主服务器发送这个ID,如果不同则进行完整重同步(之前的主服务器由于某些原因连接断开,重新选举的情况),相同则部分重同步。

服务器每次运行都会生成一个runID,如果主服务器重启因为runID发生变化会导致所有从服务器发生全量复制,因此可以将runID持久化到RDB文件中,就算服务器重启也能保证runID不变。

9.2.2PSYNC命令的实现

PSYNC命令调用方法有两种:

  • 从服务器第一次复制时,会发送PSYNC ? -1命令,请求完整重同步。
  • 已经复制过的情况,向主服务器发送PSYNC <runid> <offset>命令,一个是主服务器运行ID,一个是积压缓冲区的偏移量。

主服务器接收后有3种返回值:

  • +FULLRESYNC :表示执行完整重同步,从服务器会将这两个变量保存。
  • +CONTINUE:执行部分重同步,从服务器等待缺失数据的发送。
  • -ERR:主服务器版本低于2.8,执行完整重同步操作。

image.png
一次完整的主从复制过程
一次完整的复制过程可以分为建立连接(设置主服务器的地址和端口、建立套接字连接、发送PING命令、身份验证、发送端口信息)、同步、命令传播。
1.设置主服务器的地址和端口
当客户端向服务器发送SLAVEOF命令时,从服务器会将主服务器的ip和端口都保存后发送OK。这是一个异步命令,所以复制工作在回复OK后再执行。
2.建立套接字连接
从服务器此时创建连接主服务器的套接字,如果套接字能成功连接,从服务器会给它关联一个处理复制工作的文件事件处理器(负责接收RDB,传播的命令等)。主从成功连接后,主服务器会创建从服务器的客户端状态。
3.发送PING命令
从服务器在套接字连接后做的第一个工作就是发送PING命令,检查套接字读写状态是否正常;主服务器能否正常处理命令请求。而主服务器会根据网络状态、能够处理给出对应回复。一旦回复超时或返回错误,从服务器就会断开并重连主服务器。
4.身份验证
检查从服务器是否设置masterauth,如果设置则进行身份验证。
5.发送端口信息
身份验证后,从服务器向主服务器发送自己监听的端口号,主服务器保存这个端口号。

同步
从服务器发送PSYNC命令,主从互相成为对方的客户端,都能够执行命令并回复,执行同步操作,看是完整重同步还是部分重同步。

命令传播
完成同步后,进入该阶段,主服务器将写命令发送给从服务器,从服务器接收并执行。

主从复制的好处:

  • 读写分离:master写、slave读,提高服务器的读写负载能力
  • 负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个从节点分担数据读取负载,大大提高Redis服务器并发量与数据吞吐量
  • 故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复
  • 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
  • 高可用基石:基于主从复制,构建哨兵模式与集群,实现Redis的高可用方案

9.3心跳检测

在命令传播阶段,从服务器默认1秒一次发送REPLCONF ACK <replication_offset>命令给主服务器,replication_offset是复制偏移量。这么做有3个作用:

  • 检测主从网络状态
  • 辅助实现min-slave选项
  • 检测命令丢失

检测主从网络状态
如果主服务器超过一秒没受到从服务器的REPLCONF ACK则表示连接有问题。

辅助实现min-slave选项
Redis的min-slaves-to-write和min-slaves-max-lag可防止主服务器在不安全的情况下执行写命令。如果设置如下:
min-slaves-to-write 3 min-slaves-max-lag 10
表示从服务器数量少于3或3个从服务器延迟大于等于10s时,主服务器拒绝写命令。

检测命令丢失
通过发送的偏移量,主服务器会判断命令是否有丢失,如果丢失,就从积压缓冲区里找到并补发
注:Redis2.8之前版本并不会注意到丢失数据,所以保持主从数据一致性最好使用以上版本。
image.png
综上,完整的复制流程是

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值