Redis的增量复制

本文内容出自李子骅的《Redis入门指南》

一、什么是复制

这里的复制指的是Redis的复制功能:Redis可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他数据库上。

二、主从模式

在复制的概念里,数据库可以分为两种角色,一种是主数据库master,一种是从数据库slave。

主数据库可以进行读写操作,而从数据只能读

在读写分离模式,主数据库只负责读,从数据库只负责写。

现实业务中,读的频率大于写的频率,比例大概为8:2。

而当单机的Redis无法应付大量的读请求时,可以通过复制功能建立多个从数据库,实现读写分离,以提高服务器的负载能力。

这种一主多从的结构很适合读多写少的场景,而当单个的master不能满足需求时,可以采用Redis的集群功能。

三、复制原理

3.1 复制初始化

  • 当一个slave启动后,会向master发送SYNC命令。

  • master收到SYNC命令后,会开始在后台保存RDB快照,并将保存快照期间接收的命令缓存起来。

    保存RDB快照,即RDB持久化的过程。
    这个过程是异步的,Redis会新开一条线程负责快照。主线程仍然可以接收客户端传来的命令。

  • 快照完成后,master把快照文件和缓存的命令发送给slave。

  • slave接收到后,会载入RDB文件,并执行收到的缓存的命令

3.2 复制同步

当slave完成复制初始化后,master每当收到写命令时就会将命令同步给slave,从而保持主从数据库数据一致。

这个过程就是复制同步阶段

四、连接断开重连

当主从数据库之间的连接断开重连后,Redis2.6及之前的版本会重新进行复制初始化,即便slave仅有几条命令没有收到,master也必须要将数据库里的所有数据重新传送给slave。

这使得主从数据库断开重连后的数据恢复过程效率低下,在网络环境不好的时候这一问题尤其明显。

Redis2.8版的一个重要改进就是断线之后能够支持有条件的增量数据传输,当slave重新连上master后,master只需将断线期间执行的命令发送给slave,从而大大提高Redis复制的实用性。

五、增量复制的实现原理

5.1 实现基础

  1. slave会存储master的运行ID(run id)。

    每个Redis运行实例都会有一个唯一的运行ID。而且重启后,会自动生成一个新的运行ID。

  2. 在复制同步阶段,master每将一个命令传送给slave时,都会把该命令存放到一个积压队列(backlog)中,并记录当前积压队列存放的命令的偏移量范围。

  3. slave在收到master传来的命令时,会记录下该命令的偏移量

上面三点是实现增量复制的基础。在复制初始化时,一个slave启动后,会向master发送SYNC命令。2.8之后,Redis不再发送SYNC命令,而是发送PSYNC命令。

其格式大概为PSYNC MasterRunID [断开前最新的命令偏移量]”

5.2 实现

master收到PSYNC命令后,会执行以下判断来决定是否可以执行增量复制

  1. master会判断PSYNC中的runID是否和自己的RunID相同。

    这一步的意义在于确保slave之前的确是和自己同步的,以免slave拿到错误的数据。
    比如master在断线期间重启过,会造成数据的不一致。

  2. 判断最后同步成功的命令是否在积压队列中。如果在则可以执行增量复制,并将积压队列中相应的命令发送给slave。

5.3 积压队列

积压队列本质上是一个固定长度的循环队列,默认情况下积压队列的大小为1MB,可以通过配置文件的repi-backlog-size选项来调整。

容易理解的是,积压队列越大,其允许的主从数据库断线的时间就越长。根据主从数据库之间的网络状态,设置一个合理的积压队列很重要。因为积压队列存储的内容是命令本身,如SET foo bar,所以估算积压队列的大小只需要估计主从数据库断线时间内master可能执行的命令大小即可。

与积压队列相关的另一个配置选项是repi-backlog-ttl,即当所有的slave与master断开连接之后,经过多久才释放积压队列的内存空间。默认是1小时。

posted @ 2021-11-17 21:07  金鱼同学  阅读(869)  评论(0编辑  收藏  举报