Redis-14丨Redis复制原理

Posted by jiefang on January 16, 2020

Redis复制原理

Redis为了满足故障恢复和负载均衡的需求提供了复制功能,实现了相同数据的多个Redis副本,复制功能是高可用Redis的基础。

配置

建立复制

参与复制的Redis实例划分为主节点(master)和从节点(slave)。默认情况下,Redis都是主节点。每个从节点只能有一个主节点,而主节点可以同时具有多个从节点。

  • 在配置文件中加入slaveof{masterHost}{masterPort}随Redis启动生效;
  • 在redis-server启动命令后加入--slaveof{masterHost}{masterPort}生效;
  • 直接使用命令:slaveof{masterHost}{masterPort}生效;

断开复制

slaveof命令不但可以建立复制,还可以在从节点执行slaveof no one来断开与主节点复制关系。

断开复制主要流程:

  • 断开与主节点复制关系。
  • 从节点晋升为主节点。

通过slaveof命令还可以实现切主操作,所谓切主是指把当前从节点对主节点的复制切换到另一个主节点。执行slaveof{newMasterIp}{newMasterPort}命令即可。

切主操作流程如下:

  • 断开与旧主节点复制关系;
  • 与新主节点建立复制关系;
  • 删除从节点当前所有数据;
  • 对新主节点进行复制操作;

原理

复制过程

复制原理

  1. 保存主节点(master)信息:执行slaveof后从节点只保存主节点的地址信息便直接返回,这时建立复制流程还没有开始。
  2. 主从建立socket连接:从节点(slave)内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接。发送socket到主节点(master)的24555端口建立连接。如果从节点无法建立连接,定时任务会无限重试直到连接成功或者执行slaveof no one取消复制。
  3. 发送ping命令:连接建立成功后从节点发送ping请求进行首次通信,ping请求主要目的 如下:
    • 检测主从之间网络套接字是否可用;
    • 检测主节点当前是否可接受处理命令;
  4. 权限验证:如果主节点设置了requirepass参数,则需要密码验证,从节点必须配置masterauth参数保证与主节点相同的密码才能通过验证;如果验证失败复制将终止,从节点重新发起复制流程。
  5. 同步数据集:主从复制连接正常通信后,对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点,这部分操作是耗时最长的步骤。Redis在2.8版本以后采用新复制命令psync进行数据同步,原来的sync命令依然支持。
  6. 命令持续复制:当主节点把当前的数据同步给从节点后,便完成了复制的建立流程。接下来主节点会持续地把写命令发送给从节点,保证主从数据一致性。

数据同步

Redis在2.8及以上版本使用psync命令完成主从数据同步,同步过程分 为:全量复制部分复制

  • 全量复制:一般用于初次复制场景,Redis早期支持的复制功能只有全量复制,它会把主节点全部数据一次性发送给从节点,当数据量较大时,会对主从节点和网络造成很大的开销。
  • 部分复制:用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果条件允许,主节点会补发丢失数据给从节点。因为补发的数据远远小于全量数据,可以有效避免全量复制的过高开销。

psync命令运行需要以下组件支持:

  • 主从节点各自复制偏移量;
  • 主节点复制积压缓冲区;
  • 主节点运行id;

复制偏移量

参与复制的主从节点都会维护自身复制偏移量。主节点(master)在处 369 理完写入命令后,会把命令的字节长度做累加记录,统计信息在info relication中的master_repl_offset指标中:

1
2
3
4
5
127.0.0.1:6379> info replication
# Replication
role:master
...
master_repl_offset:1055130

从节点(slave)每秒钟上报自身的复制偏移量给主节点,因此主节点 也会保存从节点的复制偏移量,统计指标如下:

1
2
3
4
127.0.0.1:6379> info replication
connected_slaves:1
slave0:ip=127.0.0.1,port=6380,state=online,offset=1055214,lag=1 
...

从节点在接收到主节点发送的命令后,也会累加记录自身的偏移量。统 计信息在info relication中的slave_repl_offset指标中:

1
2
3
4
5
127.0.0.1:6380> info replication
# Replication
role:slave
...
slave_repl_offset:1055214

通过对比主从节点的复制偏移量,可以判断主从节点数据是否一致。

复制积压缓冲区

复制积压缓冲区是保存在主节点上的一个固定长度的队列,默认大小为 1MB,当主节点有连接的从节点(slave)时被创建,这时主节点(master) 响应写命令时,不但会把命令发送给从节点,还会写入复制积压缓冲区。 复制缓冲区相关统计信息保存在主节点的info replication中:

1
2
3
4
5
6
7
8
127.0.0.1:6379> info replication 
# Replication
role:master
...
repl_backlog_active:1 // 开启复制缓冲区
repl_backlog_size:1048576 // 缓冲区最大长度
repl_backlog_first_byte_offset:7479 // 起始偏移量,计算当前缓冲区可用范围 
repl_backlog_histlen:1048576 // 已保存数据的有效长度。

复制积压缓冲区内的可用偏移量范围: [repl_backlog_first_byte_offset, repl_backlog_first_byte_offset+repl_backlog_histlen]。

主节点运行ID

每个Redis节点启动后都会动态分配一个40位的十六进制字符串作为运 行ID。运行ID的主要作用是用来唯一识别Redis节点,比如从节点保存主节 点的运行ID识别自己正在复制的是哪个主节点。如果只使用ip+port的方式识 别主节点,那么主节点重启变更了整体数据集,从节点再基于偏移量复制数据将是不安全的,因此当运行ID变化后从节点将 做全量复制。

psync命令

从节点使用psync命令完成部分复制和全量复制功能,命令格式: psync{runId}{offset},参数含义如下:

  • runId:从节点所复制主节点的运行id;
  • offset:当前从节点已复制的数据偏移量;
    1. 从节点(slave)发送psync命令给主节点,参数runId是当前从节点保 存的主节点运行ID,如果没有则默认值为,参数offset是当前从节点保存的 复制偏移量,如果是第一次参与复制则默认值为-1;
    2. 主节点(master)根据psync参数和自身数据情况决定响应结果:
    • 如果回复+FULLRESYNC{runId}{offset},那么从节点将触发全量复制流程;
    • 如果回复+CONTINUE,从节点将触发部分复制流程;
    • 如果回复+ERR,说明主节点版本低于Redis2.8,无法识别psync命令, 从节点将发送旧版的sync命令触发全量复制流程;

全量复制

全量复制是Redis最早支持的复制方式,也是主从第一次建立复制时必 须经历的阶段。触发全量复制的命令是syncpsync。redis版本低于2.8使用sync命令;redis版本大于等于2.8使用psync命令。

  1. 发送psync命令进行数据同步,由于是第一次进行复制,从节点没有复制偏移量和主节点的运行ID,所以发送psync-1;
  2. 主节点根据psync-1解析出当前为全量复制,回复+FULLRESYNC响应;
  3. 从节点接收主节点的响应数据保存运行ID和偏移量offset;
  4. 主节点执行bgsave保存RDB文件到本地;
  5. 主节点发送RDB文件给从节点,从节点把接收的RDB文件保存在本 地并直接作为从节点的数据文件;
  6. 对于从节点开始接收RDB快照到接收完成期间,主节点仍然响应读写命令,因此主节点会把这期间写命令数据保存在复制客户端缓冲区内,当从节点加载完RDB文件后,主节点再把缓冲区内的数据发送给从节点,保证主从之间数据一致性;
  7. 从节点接收完主节点传送来的全部数据后会清空自身旧数据;
  8. 从节点清空数据后开始加载RDB文件;
  9. 从节点成功加载完RDB后,如果当前节点开启了AOF持久化功能, 它会立刻做bgrewriteaof操作,为了保证全量复制后AOF持久化文件立刻可用;

无盘复制:为了降低主节点磁盘开销,Redis支持无盘复制,生成的RDB文件不保存到硬盘而是直接通过网络发送给从节点,通过repl- diskless-sync参数控制,默认关闭。无盘复制适用于主节点所在机器磁盘性能较差但网络带宽较充裕的场景。

时间开销主要包括:

  • 主节点bgsave时间;
  • RDB文件网络传输时间;
  • 从节点清空数据时间;
  • 从节点加载RDB的时间;
  • 可能的AOF重写时间;

部分复制

部分复制主要是Redis针对全量复制的过高开销做出的一种优化措施, 使用psync{runId}{offset}命令实现。

  1. 当主从节点之间网络出现中断时,如果超过repl-timeout时间,主节点会认为从节点故障并中断复制连接;
  2. 主从连接中断期间主节点依然响应命令,但因复制连接中断命令无 法发送给从节点,不过主节点内部存在的复制积压缓冲区,依然可以保存最 近一段时间的写命令数据,默认最大缓存1MB;
  3. 当主从节点网络恢复后,从节点会再次连上主节点;
  4. 当主从连接恢复后,由于从节点之前保存了自身已复制的偏移量和 主节点的运行ID。因此会把它们当作psync参数发送给主节点,要求进行部分复制操作;
  5. 主节点接到psync命令后首先核对参数runId是否与自身一致,如果一 致,说明之前复制的是当前主节点;之后根据参数offset在自身复制积压缓 冲区查找,如果偏移量之后的数据存在缓冲区中,则对从节点发送+CONTINUE响应,表示可以进行部分复制;
  6. 主节点根据偏移量把复制积压缓冲区里的数据发送给从节点,保证主从复制进入正常状态;

心跳

主从节点在建立复制后,它们之间维护着长连接并彼此发送心跳命令。 主从心跳判断机制:

  • 主从节点彼此都有心跳检测机制,各自模拟成对方的客户端进行通 信,通过client list命令查看复制相关客户端信息,主节点的连接状态为 flags=M,从节点连接状态为flags=S;
  • 主节点默认每隔10秒对从节点发送ping命令,判断从节点的存活性 和连接状态。可通过参数repl-ping-slave-period控制发送频率;
  • 从节点在主线程中每隔1秒发送replconf ack{offset}命令,给主节点 上报自身当前的复制偏移量;replconf命令主要作用:
    • 实时监测主从节点网络状态;
    • 上报自身复制偏移量,检查复制数据是否丢失,如果从节点数据丢 失,再从主节点的复制缓冲区中拉取丢失数据;
    • 实现保证从节点的数量和延迟性功能,通过min-slaves-to-writemin- slaves-max-lag参数配置定义;

异步复制

主节点不但负责数据读写,还负责把写命令同步给从节点。写命令的发送过程是异步完成,也就是说主节点自身处理完写命令后直接返回给客户端,并不等待从节点复制完成。

主节点复制流程:

  1. 主节点接收处理命令;
  2. 命令处理完之后返回响应结果;
  3. 对于修改命令异步发送给从节点,从节点在主线程中执行复制的命令;

在主节点执行info replication命令查看延迟多少字节。

1
slave0:ip=127.0.0.1,port=6380,state=online,offset=841,lag=1 master_repl_offset:841
  • offset表示当前从节点的复制偏移量;
  • master_repl_offset表示当前主节点的复制偏移量,两者的差值就是当前从节点复制延迟量;