Redis主从复制

1. 主从复制介绍

存在的问题:

互联网项目老生常谈的三高问题:

  • 高可用
  • 高性能
  • 高并发

那么对于单点的Redis 服务器,有什么问题呢?

  • 问题1.机器故障 (硬盘故障、系统崩溃 )

导致数据丢失,很可能对业务造成灾难性打击

  • 问题2.容量瓶颈 (:内存不足,从16G升级到64G,从64G升级到128G,无限升级内存 )

    达到单台电脑硬件瓶颈

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

主从复制概念:

结构图如下:

1611151270522

共有两个角色:

  • 提供数据方:master 主服务器主节点
    • 职责:写数据
    • 执行写操作时,将出现变化的数据自动同步到slave
    • 读数据(可忽略)
  • 接收数据方:slave 从服务器,从节点
    • 读数据
    • 写数据(禁止)

主从复制即由master服务器提供写操作,由slave服务器提供读操作,并且将master中的数据即时、有效的复制到slave中 ,一个master可以拥有多个slave,一个slave只对应一个master

主要作用

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

主从复制三个主要阶段

Redis 主从复制大体可以分为三个阶段:

  1. 建立连接阶段
  2. 数据同步阶段
  3. 命令传播阶段

2. 建立连接阶段

建立slave到master的连接,使master能够识别slave,并保存slave端口号

建立连接阶段工作流程

  1. slave发送指令:slaveof ip port (master 的ip和端口)
  2. master:接收到指令,响应对方
  3. slave :保存master的IP与端口
  4. slave :根据保存的信息创建连接master的socket
  5. slave: 周期性发送命令:ping
  6. master: 响应pong
  7. slave: 发送指令:auth password
  8. master: 验证授权
  9. slave: 发送指令:replconf listening-port
  10. master: 保存slave的端口号

总结: slave保存master的地址与端口 ,master保存slave的端口 ,之间创建了连接的socket

主从连接(slave连接master)

  • 方式一:客户端发送命令

    slaveof <masterip> <masterport> //使用指令的方式,指定master的ip和端口
    
  • 方式二:启动服务器参数

    redis-server -slaveof <masterip> <masterport> //使用命令启动从服务端的时候指定master的ip和端口
    
  • 方式三:配置文件配置 (推荐)

    slaveof <masterip> <masterport> // 在从服务的配置文件中配置master
    
  • 主从断开连接

    slaveof no one // 从发送指令断开与master的连接
    

    说明: slave断开连接后,不会删除已有数据,只是不再接受master发送的数据

授权访问

master 端设置密码,从连接和使用client连接都需要密码

  • master客户端配置文件的方式

    requirepass <password> //配置文件的方式
    
  • master端使用指令

    config set requirepass <password>
    config get requirepass 
    

slave 端连接时 需要指定密码

  • slave客户端发送命令设置密码

    auth <password>
    
  • slave配置文件设置密码

    masterauth <password>
    
  • slave启动服务器设置密码

    redis-server –a <password>
    

3. 数据同步阶段

在slave初次连接master后,复制master中的所有数据到slave ,将slave的数据库状态更新成master当前的数据库状态 ,这个阶段我们称为 同步阶段

流程:

  1. slave连接上master后发送指令:psync2,请求同步数据
  2. master执行bgsave,保存数据快照
  3. master在执行bgsave前, 会创建一个复制缓冲区,用于存放在执行过程中和将RDB文件发送给slave过程中master接收的指令
  4. 生成完成RDB文件,通过socket 发送给slave
  5. slave接收RDB,清空自己的数据,然后执行RDB文件恢复过程
  6. 至此 全量复制过程完成
  7. slave在恢复RDB文件成功后,发送命令告知master RDB恢复已经完成完成
  8. master 再将之前复制缓冲区的指令发送给slave
  9. slave 接收信息,指令bgrewriteaof进行重写压缩,并恢复数据
  10. 至此 部分复制过程完成,整个同步阶段也全部结束

数据同步阶段master注意事项

  1. 如果master数据量巨大,数据同步阶段应避开流量高峰期,避免造成master阻塞,影响业务正常执行

  2. 复制缓冲区大小设定不合理(过小),会导致数据溢出(有新指令时,记录最新的指令,丢弃最老的指令)。如进行全量复制周期太长,进行部分复制时发现数据已经存在丢失的情况,必须进行第二次全量复制,致使slave陷入死循环状态。

    repl-backlog-size 1mb //master 配置文件中配置 复制缓冲区的大小
    
  3. master单机内存占用主机内存的比例不应过大,建议使用50%-70%的内存,留下30%-50%的内存用于执 行bgsave命令和创建复制缓冲区

数据同步阶段slave注意事项

  1. 为避免slave进行全量复制、部分复制时服务器响应阻塞或数据不同步,建议关闭此期间的对外服务

    slave-serve-stale-data yes|no  //设置为no 时,阻塞绝大多数请求
    
  2. 数据同步阶段,master发送给slave信息可以理解master是slave的一个客户端,主动向slave发送 命令

  3. 多个slave同时对master请求数据同步,master发送的RDB文件增多,会对带宽造成巨大冲击,如果 master带宽不足,因此数据同步需要根据业务需求,适量错峰

  4. slave过多时,建议调整拓扑结构,由一主多从结构变为树状结构,中间的节点既是master,也是 slave。注意使用树状结构时,由于层级深度,导致深度越高的slave与最顶层master间数据同步延迟 较大,数据一致性变差,应谨慎选择

4. 命令传播阶段

当master数据库状态被修改后,导致主从服务器数据库状态不一致,此时需要让主从数据同步到一致的 状态,同步的动作称为命令传播

master将接收到的数据变更命令发送给slave,slave接收命令后执行命令

但是在命令传播阶段有可能出现的断网情况

  • 网络闪断闪连 , 解决方式;忽略
  • 短时间网络中断 ,解决方式;部分复制
  • 长时间网络中断 ,解决方式;全量复制

要说清楚命令传播阶段的 部分复制, 需要了解

  • 服务器运行ID(runid)
  • 复制缓冲区/复制缓冲区偏移量

服务器运行ID(runid)

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

组成:运行id由40位字符组成,是一个随机的十六进制字符

  • 例如:fdc9ff13b9bbaab28db42b3d50f852bb5e3fcdce

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

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

复制缓冲区/复制缓冲区偏移量

概念:复制缓冲区,又名复制积压缓冲区,是一个先进先出(FIFO)的队列,用于存储服务器执行过的命令,每次master指令命令后,由master中的一个命令传统程序将命令传播给各个slave,

同时将命令记录在缓冲区中,将传播的命令记录下来

示意图:

1611758355133

工作原理:

master将每个指令,转换为RESP协议指令,依次存放到缓冲中,并对每个字节值,都维护着其一个偏移量索引, 命令传播到哪,就指向哪, master和slave 都将维护一份.master记录已发送的信息对应的offset ,slave记录已接收的信息对应的offset

如下图:

1611758001762

复制偏移量(offset)

上面介绍到,用于描述复制缓冲区中的指令字节位置

分类:

  • master复制偏移量:记录发送给所有slave的指令字节对应的位置(多个) ,master端每向一个slave发送一次记录一次
  • slave复制偏移量:记录slave接收master发送过来的指令字节对应的位置(一个) ,slave端每接收一次记录一次

作用:同步信息,比对master与slave的差异,当slave断线后,恢复数据使用

5. 数据同步阶段+命令传播阶段 详细说明

流程:

  1. slave首次连接master,发送指令psync2 <runid> <offset> , 指定master的runid和偏移量,但是第一次连接,此信息都是不知道的,所以第一次发送: psync2 ? -1

  2. master接收到连接请求, 执行bgsave生成RDB文件,记录当前的复制偏移量offset

  3. master 发送 +FULLRESYNC runid offset 指令,将master的runid和offset发送给slave,再通过socket发送RDB文件给slave

  4. slave 收到 +FULLRESYNC ,保存master的runid和offset, 并清空当前全部数据,通过socket接收RDB文件,恢复RDB数据

  5. 全量复制结束 (在slave全量恢复的过程中,master可能接受到了新的指令,并一直向外传播,master记录的此slave的offset发生变化)

  6. slave继续发送命令:psync2 runid offset ,这次携带了 master的runid 和 offset

  7. master接收命令,判定runid是否匹配,并判定offset是否在复制缓冲区中

    • 如果runid或offset有一个不满足,执行全量复制

    • 如果runid或offset校验通过,offset与offset都相同,忽略

    • 如果runid或offset校验通过,master存的该slave的offset与slave传过来的 offset不相同

      则说明在slave全量复制的过程中,master又传播了一些新的指令,此时master需要发送 +CONTINUE offset 指令,将master存的offset 再发送给该slave,并将两个offset之间的指令重新补发给slave

  8. 至此数据同步阶段结束

心跳机制

后续的命令传播,靠的就是主从直接的心跳机制完成,并实现双方连接保持在线

slave心跳任务:

  • 指令:REPLCONF ACK {offset} , 携带偏移量,进行同步
  • 周期:1秒
  • 作用1:汇报slave自己的复制偏移量,获取最新的数据变更指令
  • 作用2:判断master是否在线

master心跳:

  • 指令:PING
  • 周期:由repl-ping-slave-period决定,默认10秒
  • 作用:判断slave是否在线
  • 查询:INFO replication 获取slave最后一次连接时间间隔,lag项维持在0或1视为正常

心跳阶段注意事项

当slave多数掉线,或延迟过高时,master为保障数据稳定性,应该拒绝所有信息同步操作

配置文件中设置如下参数

min-slaves-to-write 2
min-slaves-max-lag 8

含义: slave在线数量少于2个,或者所有slave的延迟都大于等于8时,强制关闭master写功能,停止数据同步

slave的在线数量和slave的延迟性,都由slave的REPLCONF ACK 发送过来的

总结: 命令传播阶段的部分复制和数据同步阶段的全量复制几乎相同,只是请求的指令不同而已,如下图

1611761560191

6. 主从复制注意事项

6.1 全量复制问题

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

内部优化调整方案了解:

  1. master内部创建master_replid变量,使用runid相同的策略生成,长度41位,并发送给所有slave
  2. 在master关闭时执行命令 shutdown save,进行RDB持久化,将runid与offset保存到RDB文件中
    • repl-id 和 repl-offset
    • 通过redis-check-rdb命令可以查看该信息
  3. master重启后加载RDB文件,恢复数据 ,重启后,将RDB文件中保存的repl-id与repl-offset加载到内存中
  4. 本机保存上次runid,重启后恢复该值,使所有slave认为还是之前的master

问题2: master 复制缓冲区过小,断网或者网络延迟后slave的offset越界,触发全量复制 ,而如果频繁出现,则slave反复进行全量复制 ,slave不提供服务

解决方案:修改复制缓冲区大小

repl-backlog-size 10mb

建议设置如下:

  1. 测算从master到slave的重连平均时长second (例如2s)
  2. 获取master平均每秒产生写命令数据总量write_size_per_second (例如1mb)
  3. 最优复制缓冲区空间 = 2 * second * write_size_per_second (建议为4mb)

6.2 频繁的网络中断

问题1: master的CPU占用过高 , 例如

每个slave每1秒发送REPLCONF ACK命令到master ,

或者当slave 执行到慢查询命令时,被阻塞住(keys * ,hgetall等) ,而master在向此slave发送心跳没有响应,一直会重复发送,占用master的cpu

master每1秒调用复制定时函数replicationCron(),比对slave发现长时间没有进行响应

结果导致master各种资源(输出缓冲区、带宽、连接等)被严重占用

解决方法:

通过设置合理的超时时间,确认是否释放slave

repl-timeout 60

该参数定义了超时时间的阈值(默认60秒),超过该值,释放slave

问题2:

因为master发送ping指令频度较低 ,或者 ping指令在网络中存在丢包

并且此时master设定超时时间较短 , 将很容易导致slave与master连接断开

解决方案 :

提高ping指令发送的频度

repl-ping-slave-period 

超时时间repl-time的时间至少是ping指令频度的5到10倍,否则slave很容易判定超时

6.3 数据不一致

因为网络信息不同步,数据发送有延迟 等等,导致多个slave获取相同数据不同步

可以优化主从间的网络环境,通常放置在同一个机房部署,如使用阿里云等云服务器时要注意此现象

监控主从节点延迟(通过offset)判断,如果slave延迟过大,暂时屏蔽程序对该slave的数据访问

slave-serve-stale-data yes|no

开启后仅响应info、slaveof等少数命令(慎用,除非对数据一致性要求很高)

posted @ 2021-01-31 23:42  哈哈丶丶  阅读(92)  评论(0编辑  收藏  举报