0%

Redis-主从复制

简介

主从复制是什么?

主从复制:主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主。

Redis主从复制能做什么?

  1. 读写分离:master写,slave读,提高服务器的读写负载能力
  2. 故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复
  3. 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
  4. 高可用基石:基于主从复制,构建哨兵模式域集群,实现Redis的高可用方案

Redis主从复制实现

主从连接(slave连接master)

从节点开启主从复制,有三种方式。
分别是:配置文件,启动服务命令,客户端命令。

方式1:配置文件

在从服务器的配置文件中加入:

1
slaveof <masterip> <masterport>

方式1:启动服务命令

redis-server启动命令后加入:

1
redis-server -slaveof <masterip> <masterport>

方式3:客户端命令

Redis服务器启动后,直接通过客户端执行命令

1
slaveof <masterip> <masterport>

主从断开连接

客户端执行命令:

1
slaveof no one

实例

注意:主从复制的开启,完全是在从节点发起的,不需要我们在主节点做任何事情。

// TODO

Redis主从复制原理

  • 主从复制流程大体可以分为3个阶段
    • 建立连接阶段(即准备阶段)
    • 数据同步阶段
    • 命令传播阶段

Redis主从复制工作流程

建立连接

简介

该阶段的主要作用是在主从节点之间建立连接,为数据同步做好准备。

建立连接工作流程

建立连接工作流程

步骤1:设置master的地址和端口,保存master信息
步骤2:建立socket连接
步骤3:发送ping命令(定时器任务)
步骤4:身份验证
步骤5:发送slave端口信息
至此,主从连接成功!

数据同步

简介

主从节点之间的连接建立以后,便可以开始进行数据同步,该阶段可以理解为从节点数据的初始化。具体执行的方式是:从节点向主节点发送psync命令(Redis2.8以前是sync命令),开始同步。
数据同步阶段是主从复制最核心的阶段,根据主从节点当前状态的不同,可以分为全量复制和部分复制,下面会有一章专门讲解这两种复制方式以及psync命令的执行过程,这里不再详述。

需要注意的是:在数据同步阶段之前,从节点是主节点的客户端,主节点不是从节点的客户端;而到了这一阶段及以后,主从节点互为客户端。原因在于:在此之前,主节点只需要响应从节点的请求即可,不需要主动发请求,而在数据同步阶段和后面的命令传播阶段,主节点需要主动向从节点发送请求(如推送缓冲区中的写命令),才能完成复制。

数据同步工作流程

数据同步工作流程

步骤1:请求同步数据
步骤2:创建RDB同步数据
步骤3:恢复RDB同步数据
步骤4:请求部分同步数据
步骤5:恢复部分同步数据
至此,数据同步工作完成!

数据同步阶段master说明

  1. 如果master数据量巨大,数据同步阶段应避开流量高峰期,避免造成master阻塞,影响业务正常执行
    • repl-backlog-size 1mb
  2. 复制缓冲区大小设定不合理,会导致数据溢出。如进行全量复制周期太长,进行部分复制时发现数据已
    经存在丢失的情况,必须进行第二次全量复制,致使slave陷入死循环状态。
  3. master单机内存占用主机内存的比例不应过大,建议使用50%-70%的内存,留下30%-50%的内存用于执
    行bgsave命令和创建复制缓冲区

数据同步阶段slave说明

  1. 为避免slave进行全量复制、部分复制时服务器响应阻塞或数据不同步,建议关闭此期间的对外服务
    • slave-serve-stale-data yes|no
  2. 数据同步阶段,master发送给slave信息可以理解master是slave的一个客户端,主动向slave发送
    命令
  3. 多个slave同时对master请求数据同步,master发送的RDB文件增多,会对带宽造成巨大冲击,如果
    master带宽不足,因此数据同步需要根据业务需求,适量错峰
  4. slave过多时,建议调整拓扑结构,由一主多从结构变为树状结构,中间的节点既是master,也是
    slave。注意使用树状结构时,由于层级深度,导致深度越高的slave与最顶层master间数据同步延迟
    较大,数据一致性变差,应谨慎选择

命令传播

注意:先看[全量复制和部分复制] + [心跳机制],再看这节内容。

简介

数据同步阶段完成后,主从节点进入命令传播阶段;在这个阶段主节点将自己执行的写命令发送给从节点,从节点接收命令并执行,从而保证主从节点数据的一致性。

在命令传播阶段,除了发送写命令,主从节点还维持着心跳机制:PING和REPLCONF ACK。由于心跳机制的原理涉及部分复制,因此将在介绍了部分复制的相关内容后单独介绍该心跳机制。

延迟与数据不一致

  • 异步:需要注意的是,命令传播是异步的过程,即主节点发送写命令后并不会等待从节点的回复;
  • 数据不一致:因为是异步的,因此实际上主从节点之间很难保持实时的一致性,延迟在所难免。数据不一致的程度,与主从节点之间的网络状况、主节点写命令的执行频率、以及主节点中的repl-disable-tcp-nodelay配置等有关。

repl-disable-tcp-nodelay no

  • 该配置作用于命令传播阶段,控制主节点是否禁止与从节点的TCP_NODELAY;默认no,即不禁止TCP_NODELAY。当设置为yes时,TCP会对包进行合并从而减少带宽,但是发送的频率会降低,从节点数据延迟增加,一致性变差;具体发送频率与Linux内核的配置有关,默认配置为40ms。当设置为no时,TCP会立马将主节点的数据发送给从节点,带宽增加但延迟变小。
  • 一般来说,只有当应用对Redis数据不一致的容忍度较高,且主从节点之间网络状况不好时,才会设置为yes;多数情况使用默认值no。

命令传播工作流程

命令传播工作流程

主节点心跳流程:
主节点发送命令ping,判断从节点是否超时。

从节点心跳流程:
步骤1:从节点发送命令replconf ack offset
步骤2:主节点接受命令,判断从节点复制偏移量(offset)是否在复制缓冲区
步骤3:如果在,主节点复制偏移量(offset)和从节点复制偏移量(offset)相同,则忽略
步骤3:如果在,但主节点复制偏移量(offset)和从节点复制偏移量(offset)不同,则执行部分复制
步骤3:如果不在,则执行全量复制

全量复制和部分复制(数据同步阶段)

在Redis2.8以前,从节点向主节点发送sync命令请求同步数据,此时的同步方式是全量复制;在Redis2.8及以后,从节点可以发送psync命令请求同步数据,此时根据主从节点当前状态的不同,同步方式可能是全量复制或部分复制。

  • 全量复制:用于初次复制或其他无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作。
  • 部分复制:用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效。需要注意的是,如果网络中断时间过长,导致主节点没有能够完整地保存中断期间执行的写命令,则无法进行部分复制,仍使用全量复制。

注意:后文介绍以Redis2.8及以后版本为例。

全量复制

全量复制触发条件

  1. 第一次进行主从连接
  2. 主节点无法进行部分复制(runid或offset不满足)

全量复制流程

Redis通过psync命令进行全量复制的过程如下:

  1. 从节点判断无法进行部分复制,向主节点发送全量复制的请求;或从节点发送部分复制的请求,但主节点判断无法进行部分复制;
  2. 主节点收到全量复制的命令后,执行bgsave,在后台生成RDB文件,并使用一个缓冲区(称为复制缓冲区)记录从现在开始执行的所有写命令
  3. 主节点的bgsave执行完成后,将RDB文件发送给从节点;从节点首先清除自己的旧数据,然后载入接收的RDB文件,将数据库状态更新至主节点执行bgsave时的数据库状态
  4. 主节点将前述复制缓冲区中的所有写命令发送给从节点,从节点执行这些写命令,将数据库状态更新至主节点的最新状态
  5. 如果从节点开启了AOF,则会触发bgrewriteaof的执行,从而保证AOF文件更新至主节点的最新状态

通过全量复制的过程可以看出,全量复制是非常重型的操作:

  1. 主节点通过bgsave命令fork子进程进行RDB持久化,该过程是非常消耗CPU、内存(页表复制)、硬盘IO的;
  2. 主节点通过网络将RDB文件发送给从节点,对主从节点的带宽都会带来很大的消耗
  3. 从节点清空老数据、载入新RDB文件的过程是阻塞的,无法响应客户端的命令;如果从节点执行bgrewriteaof,也会带来额外的消耗

部分复制

由于全量复制在主节点数据量较大时效率太低,因此Redis2.8开始提供部分复制,用于处理网络中断时的数据同步。
部分复制的实现,依赖于三个重要的概念:服务器运行ID,复制积压缓存区,复制偏移量。

服务器运行ID(runid)

简介

概念:每个Redis节点(无论主从),在启动时都会自动生成一个随机ID(每次启动都不一样),由40个随机的十六进制字符组成。
作用:运行id被用于在服务器间进行传输,识别身份。

详解

主从节点初次复制时,主节点将自己的runid发送给从节点,从节点将这个runid保存起来,当断线重连时,从节点会将这个runid发送给主节点;
主节点根据runid判断能否进行部分复制:

  • 如果从节点保存的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会继续尝试使用部分复制(到底能不能部分复制还要看offset和复制积压缓冲区的情况);
  • 如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的Redis节点并不是当前的主节点,只能进行全量复制。

复制积压缓存区

简介

概念:复制积压缓冲区,又名复制缓冲区,是由主节点维护的、固定长度的、先进先出(FIFO)队列,默认大小1MB;
作用:当主节点开始有从节点时创建,是备份主节点最近发送给从节点的数据。(用于存储服务器执行过的命令,每次传播命令,master都会将传播的命令记录下来,并存储在复制缓冲区)
组成:偏移量 + 字节值

注意:无论主节点有一个还是多个从节点,都只需要一个复制积压缓冲区。

详解

复制积压缓存区详解1
复制积压缓存区详解2

在命令传播阶段,主节点除了将写命令发送给从节点,还会发送一份给复制积压缓冲区,作为写命令的备份;除了存储写命令,复制积压缓冲区中还存储了每个字节对应的复制偏移量(offset)。由于复制积压缓冲区定长且是先进先出,所以它保存的是主节点最近执行的写命令;时间较早的写命令会被挤出缓冲区。

由于该缓冲区长度固定且有限,因此可以备份的写命令也有限,当主从节点offset的差距过大超过缓冲区长度时,将无法执行部分复制,只能执行全量复制。反过来说,为了提高网络中断时部分复制执行的概率,可以根据需要增大复制积压缓冲区的大小(通过配置repl-backlog-size);例如如果网络中断的平均时间是60s,而主节点平均每秒产生的写命令(特定协议格式)所占的字节数为100KB,则复制积压缓冲区的平均需求为6MB,保险起见,可以设置为12MB,来保证绝大多数断线情况都可以使用部分复制。

从节点将offset发送给主节点后,主节点根据offset和缓冲区大小决定能否执行部分复制:

  • 如果offset偏移量之后的数据,仍然都在复制积压缓冲区里,则执行部分复制;
  • 如果offset偏移量之后的数据已不在复制积压缓冲区中(数据已被挤出),则执行全量复制。

复制偏移量(offset)

简介

概念:主节点和从节点分别维护一个复制偏移量(offset),代表的是主节点向从节点传递的字节数;
作用:主节点每次向从节点传播N个字节数据时,主节点的offset增加N;从节点每次收到主节点传来的N个字节数据时,从节点的offset增加N。

详解

offset用于判断主从节点的数据库状态是否一致:
如果二者offset相同,则一致;如果offset不同,则不一致,此时可以根据两个offset找出从节点缺少的那部分数据。例如,如果主节点的offset是1000,而从节点的offset是500,那么部分复制就需要将offset为501-1000的数据传递给从节点。

部分复制流程

在了解了节点运行id、复制积压缓冲区、复制偏移量之后,总结一下部分复制的流程:

  1. 主节点维护了一个复制缓冲区和节点id(runid),主从节点都维护了一个复制偏移量(offset)
  2. 从节点发送命令psync2 runid offset
  3. 主节点判断runid是否匹配,判断offset是否存在复制缓冲区中;如果runid或offset有一个不满足,则执行全量复制
  4. 主节点判断runid或offset校验通过,返回 +CONTINUE offset,进行部分复制,通过stocket发送复制缓冲区[从节点中复制偏移量]到[主节点复制偏移量]的数据
  5. 从节点接收到+CONTINUE,保存master的复制偏移量,并执行命令,完成同步

psync命令执行详解

在了解了节点运行id、复制积压缓冲区、复制偏移量之后,本节将介绍psync命令的参数和返回值,从而说明psync命令执行过程中,主从节点是如何确定使用全量复制还是部分复制的。

全量复制+部分复制
psync命令执行详解

  1. 首先,从节点根据当前状态,决定如何调用psync命令
    • 如果从节点之前未执行过slaveof,或最近执行了slaveof no one,则从节点发送命令为psync ? -1,向主节点请求全量复制;
    • 如果从节点之前执行了slaveof,则发送命令为psync <runid> <offset>,其中runid为上次复制的主节点的runid,offset为上次复制截止时从节点保存的复制偏移量。
  2. 主节点根据收到的psync命令,及当前服务器状态,决定执行全量复制还是部分复制
    • 如果主节点版本低于Redis2.8,则返回-ERR回复,此时从节点重新发送sync命令执行全量复制;
    • 如果主节点版本够新,且runid与从节点发送的runid相同,且从节点发送的offset之后的数据在复制积压缓冲区中都存在,则回复+CONTINUE,表示将进行部分复制,从节点等待主节点发送其缺少的数据即可;
    • 如果主节点版本够新,但是runid与从节点发送的runid不同,或从节点发送的offset之后的数据已不在复制积压缓冲区中(在队列中被挤出了),则回复+FULLRESYNC ,表示要进行全量复制,其中runid表示主节点当前的runid,offset表示主节点当前的offset,从节点保存这两个值,以备使用。

心跳机制(命令传播阶段)

简介

在命令传播阶段,除了发送写命令,主从节点还维持着心跳机制:PING和REPLCONF ACK。心跳机制对于主从复制的超时判断、数据安全等有作用。

PING(主->从)

每隔指定的时间,主节点会向从节点发送PING命令,这个PING命令的作用,主要是为了让从节点进行超时判断。。

master心跳:

  • 命令:每隔指定的时间,主节点会向从节点发送PING命令
  • 周期:PING发送的频率由repl-ping-slave-period参数控制,单位是秒,默认值是10s。
  • 作用:判断从节点是否在线

REPLCONF ACK(从->主)

slave心跳:
指令:在命令传播阶段,从节点会向主节点发送REPLCONF ACK命令,命令格式为REPLCONF ACK {offset},其中offset指从节点保存的复制偏移量
周期:频率是每秒1次
作用:

  1. 实时监测主从节点网络状态:该命令会被主节点用于复制超时的判断。此外,在主节点中使用info Replication,可以看到其从节点的状态中的lag值,代表的是主节点上次收到该REPLCONF ACK命令的时间间隔,在正常情况下,该值应该是0或1
  2. 检测命令丢失:从节点发送了自身的offset,主节点会与自己的offset对比,如果从节点数据缺失(如网络丢包),主节点会推送缺失的数据(这里也会利用复制积压缓冲区)。注意,offset和复制积压缓冲区,不仅可以用于部分复制,也可以用于处理命令丢失等情形;区别在于前者是在断线重连后进行的,而后者是在主从节点没有断线的情况下进行的。
  3. 辅助保证从节点的数量和延迟

注意事项

  • 当slave多数掉线,或延迟过高时,master为保障数据稳定性,将拒绝所有信息同步操作
    • min-slaves-to-write 2
    • min-slaves-max-lag 8
    • slave数量少于2个,或者所有slave的延迟都大于等于10秒时,强制关闭master写功能,停止数据同步
  • slave数量由slave发送REPLCONF ACK命令做确认
  • slave延迟由slave发送REPLCONF ACK命令做确认

Redis主从复制常见问题

https://www.cnblogs.com/kismetv/p/9236731.html

参考

黑马Redis视频
https://www.cnblogs.com/kismetv/p/9236731.html