Redis - 主从复制

本文探讨了单机Redis高可用性问题,指出其存在机器故障和容量瓶颈风险。为实现高可用,采用主从复制方案,介绍了主从复制的概念、作用、工作流程,包括建立连接、数据同步、命令传播阶段,还分析了部分复制的核心要素,最后阐述了频繁全量复制和缓冲区过小等常见问题及解决办法。

1. 单机Redis是否高可用?

1.1 单机redis的风险与问题

机器故障

  • 现象:硬盘故障、系统崩溃
  • 本质:数据丢失,很可能对业务造成灾难性打击
  • 结论:基本上会放弃使用redis.

问题2.容量瓶颈

  • 现象:内存不足,从16G升级到64G,从64G升级到128G,无限升级内存
  • 本质:穷,硬件条件跟不上
  • 结论:放弃使用redis

结论
为了避免单点Redis服务器故障,准备多台服务器,互相连通。将数据复制多个副本保存在不同的服 务器上,连接在一起,并保证数据是同步的。即使有其中一台服务器宕机,其他服务器依然可以继续 提供服务,实现Redis的高可用,同时实现数据冗余备份

1.2 多台服务器连接方案

  • 提供数据方:master 主服务器,主节点,主库 主客户端
  • 接收数据方:slave 从服务器,从节点,从库,从客户端
  • 需要解决的问题: 数据同步
  • 核心工作: master的数据复制到slave中
    在这里插入图片描述

2. 主从复制

2.1 概念

主从复制即将master中的数据即时、有效的复制到slave中
在这里插入图片描述

特征:一个master可以拥有多个slave,一个slave只对应一个master

master:

  • 写数据
  • 执行写操作时,将出现变化的数据自动同步到slave
  • 读数据(可忽略)

slave:

  • 读数据
  • 写数据(禁止)

2.2 作用

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

3. 主从复制的工作流程

主从复制过程大体可以分为3个阶段

  • 建立连接阶段(即准备阶段)(slave连master,因为是slave不断加入)
  • 数据同步阶段 (主从节点之间的连接建立以后,便可以开始进行数据同步,该阶段可以理解为从节点数据的初始化)
  • 命令传播阶段(反复同步,在这个阶段主节点将自己执行的写命令发送给从节点,从节点接收命令并执行,从而保证主从节点数据的一致性)
    在这里插入图片描述

① 建立连接

主从复制的开启,完全是在从节点发起的;不需要我们在主节点做任何事情
从节点开启主从复制,有3种方式:

  1. 配置文件
在从服务器的配置文件中加入:slaveof <masterip> <masterport>
  1. 启动命令
redis-server启动命令后加入 --slaveof <masterip> <masterport>
  1. 客户端命令
Redis服务器启动后,直接通过客户端执行命令:slaveof <masterip> <masterport>,则该Redis实例成为从节点。

在这里插入图片描述
步骤1:保存主节点信息
从节点服务器内部维护了两个字段,即masterhost和masterport字段,用于存储主节点的ip和port信息。

需要注意的是,slaveof是异步命令,从节点完成主节点ip和port的保存后,向发送slaveof命令的客户端直接返回OK,实际的复制操作在这之后才开始进行。

步骤2:建立socket连接
从节点每秒1次调用复制定时函数replicationCron(),如果发现了有主节点可以连接,便会根据主节点的ip和port,创建socket连接。如果连接成功,则:

  • 从节点:为该socket建立一个专门处理复制工作的文件事件处理器,负责后续的复制工作,如接收RDB文件、接收命令传播等。

  • 主节点:接收到从节点的socket连接后(即accept之后),为该socket创建相应的客户端状态,并将从节点看做是连接到主节点的一个客户端,后面的步骤会以从节点向主节点发送命令请求的形式来进行。

步骤3:发送ping命令
从节点成为主节点的客户端之后,发送ping命令进行首次请求,目的是:检查socket连接是否可用,以及主节点当前是否能够处理请求。

从节点发送ping命令后,可能出现3种情况:

(1)返回pong:说明socket连接正常,且主节点当前可以处理请求,复制过程继续。

(2)超时:一定时间后从节点仍未收到主节点的回复,说明socket连接不可用,则从节点断开socket连接,并重连。

(3)返回pong以外的结果:如果主节点返回其他结果,如正在处理超时运行的脚本,说明主节点当前无法处理命令,则从节点断开socket连接,并重连

步骤4:身份验证
如果从节点中设置了masterauth选项,则从节点需要向主节点进行身份验证;没有设置该选项,则不需要验证。从节点进行身份验证是通过向主节点发送auth命令进行的,auth命令的参数即为配置文件中的masterauth的值。

如果主节点设置密码的状态,与从节点masterauth的状态一致(一致是指都存在,且密码相同,或者都不存在),则身份验证通过,复制过程继续;如果不一致,则从节点断开socket连接,并重连。

步骤5:发送从节点端口信息
身份验证之后,从节点会向主节点发送其监听的端口号(前述例子中为6380),主节点将该信息保存到该从节点对应的客户端的slave_listening_port字段中;该端口信息除了在主节点中执行info Replication时显示以外,没有其他作用

② 数据同步

主从节点之间的连接建立以后,便可以开始进行数据同步

在slave初次连接master后,复制master中的所有数据到slave,该阶段可以理解为从节点数据的初始化,将slave的数据库状态更新成master当前的数据库状态

具体执行的方式是:从节点向主节点发送psync 2命令(Redis2.8以前是sync命令),开始同步。

数据同步阶段是主从复制最核心的阶段,根据主从节点当前状态的不同,可以分为全量复制和部分复制
在这里插入图片描述
全量复制:获取发送同步指令那一刻前的所有的数据
用于初次复制或其他无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作

  1. 主节点收到全量复制的命令后,执行bgsave,在后台生成RDB文件,但是在这个时候master有可能还在接收指令,所以使用一个缓冲区(称为复制缓冲区)记录从现在开始master接受的所有命令(相当于记录的是AOF)
  2. 主节点的bgsave执行完成后,通过socket将RDB文件发送给从节点;从节点首先清除自己的旧数据,然后载入接收的RDB文件,将数据库状态更新至主节点执行bgsave时的数据库状态

部分复制:获取RDB过程中新发送的数据,通过复制缓冲区实现,请求部分同步数据
3. 主节点将前述复制缓冲区中的所有写命令发送给从节点,从节点执行这些写命令,将数据库状态更新至主节点的最新状态,注意,因为复制缓冲区存储的是指令,所以相当于存储的是AOF,发送给从节点后,从节点进行重写
4. 如果从节点开启了AOF,则会触发bgrewriteaof的执行,从而保证AOF文件更新至主节点的最新状态

数据同步阶段master说明

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

数据同步阶段slave说明

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

③ 命令传播阶段 - 实时保证数据同步

数据同步阶段完成后,主从节点进入命令传播阶段;
由于master节点对外提供写服务,当master数据库的状态被修改后导致主从服务器状态不一致,此时需要让主从数据同步到一致的状态,同步的动作称为命令传播

命令传播阶段 - 心跳机制

在命令传播阶段,除了发送写命令,主从节点还维持着心跳机制:PING和REPLCONF ACK。心跳机制对于主从复制的超时判断、数据安全等有作用
主->从:PING
每隔指定的时间,主节点会向从节点发送PING命令,这个PING命令的作用,主要是为了让从节点进行超时判断

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

  1. 实时监测主从节点网络状态:该命令会被主节点用于复制超时的判断。此外,在主节点中使用info Replication,可以看到其从节点的状态中的lag值,代表的是主节点上次收到该REPLCONF ACK命令的时间间隔,在正常情况下,该值应该是0或1

  2. 检测命令丢失:从节点发送了自身的offset,主节点会与自己的offset对比,如果从节点数据缺失(如网络丢包),主节点会推送缺失的数据(这里也会利用复制积压缓冲区)。注意,offset和复制积压缓冲区,不仅可以用于部分复制,也可以用于处理命令丢失等情形;区别在于前者是在断线重连后进行的,而后者是在主从节点没有断线的情况下进行的。

命令传播阶段的部分复制
在命令传播阶段也可能会出现部分复制的情况,比如断网了,master的指令没有实时的发送给slave

场景解决方案
网络闪断闪连忽略
短时间网络中断部分复制
长时间网络中断全量复制
  • 短时间中断命令在master的复制缓冲区还有,所以可以通过部分复制恢复数据
  • 长时间中断命令在缓冲区存储不下,所以要使用全量复制

部分复制详解

部分复制有三个核心要素:

  • 服务器的运行id
  • 主服务器的复制积压缓冲区
  • 主从服务器的复制偏移量

服务运行id
概念:服务器运行ID是每一台服务器每次运行的身份识别码,一台服务器多次运行可以生成多个运行id

作用:运行id被用于在服务器间进行传输,识别身份 如果想两次操作均对同一台服务器进行,必须每次操作携带对应的运行id,用于对方识别

实现方式:运行id在每台服务器启动时自动生成的,master在首次连接slave时,会将自己的运行ID发 送给slave,slave保存此ID,通过info Server命令,可以查看节点的runid

主服务器的复制积压缓冲区
复制缓冲区,又名复制积压缓冲区,主节点维护的、固定长度的、先进先出(FIFO)队列,默认大小1MB,用于存储服务器执行过的命令

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

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

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

  • 如果offset偏移量之后的数据,仍然都在复制积压缓冲区里,则执行部分复制;
  • 如果offset偏移量之后的数据已不在复制积压缓冲区中(数据已被挤出),则执行全量复制
    在这里插入图片描述
    偏移量
    在这里插入图片描述
    主节点和从节点分别维护一个复制偏移量(offset),代表的是主节点向从节点传递的字节数;主节点每次向从节点传播N个字节数据时,主节点的offset增加N;从节点每次收到主节点传来的N个字节数据时,从节点的offset增加N。

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

④ 数据同步+命令传播阶段工作流程

在这里插入图片描述
首先,从节点根据当前状态,决定如何调用psync命令:

  • 如果从节点之前未执行过slaveof或最近执行了slaveof no one,则从节点发送命令为psync2 ? -1,向主节点请求全量复制;
  • 如果从节点之前执行了slaveof,则发送命令为psync2 ,其中runid为上次复制的主节点的runid,offset为上次复制截止时从节点保存的复制偏移量。

主节点根据收到的psync2命令,及当前服务器状态,决定执行全量复制还是部分复制:

  • 如果主节点版本低于Redis2.8,则返回-ERR回复,此时从节点重新发送sync2命令执行全量复制;
  • 如果主节点版本够新,且runid与从节点发送的runid相同,且从节点发送的offset之后的数据在复制积压缓冲区中都存在,则回复+CONTINUE,表示将进行部分复制,从节点等待主节点发送其缺少的数据即可;
  • 如果主节点版本够新,但是runid与从节点发送的runid不同,或从节点发送的offset之后的数据已不在复制积压缓冲区中(在队列中被挤出了),则回复+FULLRESYNC ,表示要进行全量复制,其中runid表示主节点当前的runid,offset表示主节点当前的offset,从节点保存这两个值,以备使用。
    在这里插入图片描述
    在这里插入图片描述

4. 主从复制常见问题

4.1 频繁的全量复制

伴随着系统的运行,master的数据量会越来越大,一旦master重启,runid将发生变化,会导致全部slave的 全量复制操作

内部优化调整方案:

  1. master内部创建master_replid变量,使用runid相同的策略生成,长度41位,并发送给所有slave
  2. 在master关闭时执行命令 shutdown save,进行RDB持久化,将runid与offset保存到RDB文件中
  3. master重启后加载RDB文件,恢复数据 重启后,将RDB文件中保存的repl-id与repl-offset加载到内存中

**作用:**本机保存上次runid,重启后恢复该值,使所有slave认为还是之前的master

4.2 缓冲区过小

复制缓冲区过小,断网后slave的offset越界,触发全量复制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值