首页 > 技术文章 > redis专题十三:redis的主从复制

leijisong 2020-11-22 11:11 原文

之前章节我们都是操作单机的redis,这一节开始将开始关注redis集群相关的内容,这一节主要讲述集群的基础——主从复制。

一、主从复制简介

1.1 单机可能出现的问题 

单机的redis不可避免地可能会出现一些问题,比方说:

  • 机器故障、服务器宕机,数据丢失,很可能对业务造成灾难性的打击;
  • 容量瓶颈,内存不足,不可能无限升级内存,硬件跟不上;

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

1.2 多台服务器的连接方案

我们找多台计算机连接起来,专门用一台计算机负责负责收集数据(master服务器),其他计算机负责读数据(slave服务器);slave的数据从master上来,这样就保证了高可用;

这个过程需要解决的问题:数据同步问题,而核心工作就是master端的数据能够复制到slave中去。这就是我们说的主从复制。

主从复制就是将master中的数据即时、有效的复制到slave中去。

特征:一个master可以有多个slave,但是一个slave只能有一个master。

职责:

  • master:负责写数据,执行写操作,将出现变化的数据同步到slave;
  • slave:负责读数据,会配置禁止写数据,原因是如果多个slave都在写,那么很难有效保证多个slave之间的数据一致性。

那可能说,为什么不多搞几个master?是的,是可以的,相当于master本身也是一个集群,之后我们在哨兵的章节详细讨论。

1.3 主从复制的作用

  • 实现读写分离,master写,slave读,提高服务器的读写负载能力
  • 实现负载均衡,基于主从结构,配合读写分离,由slave分担master的负载,并根据需求变化,改变slave的数量,大大提高redis的并发量和数据吞吐量;
  • 故障恢复快,当master出现问题,可以由slave提供服务;
  • 数据冗余,实现了数据的热备份
  • 实现redis的高可用:基于主从复制,构建哨兵模式与集群,实现高可用

二、主从复制的原理

 主从复制分为三个阶段:

  • 建立连接阶段:salve向master发起连接
  • 数据同步阶段:master向slave同步数据
  • 命令传播阶段:后期master收到的数据,也要同步给slave,这是一个反复的过程;

 2.1 建立连接阶段

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

  • slave 发送指令:salveof ip port  ,这个指令就是将一台服务器变成另一台服务器的从;master接受到指令后做出回应
  • slave保存master的IP和端口信息,根据保存的信息创建连接master的socket
  • salve周期性的向master发送ping指令(定时),保证连接是一直存在的
  • 如果master配置了身份验证,slave需要完成相应鉴权
  • 最后,slave发送指令告诉master通过端口完成对slave的监听,master接收后保存salve的端口号;

总的来说:salve保存master的地址和端口,master保存slave的端口,他们之间创建socket连接;

2.1.2 具体操作简介

主从连接方案:(slave连接master)

连接方案 说明
客户端发送指令 slaveof masterip masterport
启动服务器参数 redis-server -slaveof masterip masterport
服务器配置(推荐) slaveof masterip masterport

2.1.3 授权访问

master:

  • master配置文件设置密码:requirepass  <password>
  • master客户端发送命令设置密码:config set requirepass <password>  获取使用 config get requirepass

slave:

  • salve客户端发送命令设置密码:auth <password>
  • salve配置文件设置密码:masterauth <password>
  • 启动客户端设置密码:redis-cli -a <password>

 2.2 数据同步阶段

 2.2.1 工作流程:

  • 在slave初次连接master后,复制master中的所有数据到slave
  • 将slave的数据库状态更新成master当前的数据库状态

 2.2.2 详细说明:

  1. slave向master发送指令:psync2;slave请求同步数据
  2. master执行bgsave,这个时候master可能还会持续接受数据,为了防止数据无法给到slave,master创建一个复制缓冲区来接受指令;master则可以放心做RDB的过程,生成RDB文件,通过socket发送给slave
  3. slave接收RDB,清空文件,执行RDB文件恢复过程;这个过程是一个全量复制的过程
  4. slave发送指令告诉master RDB已经结束,请求master是否还有没有同步的数据;
  5. master把复制缓冲区信息,slave接收信息,指令重写(bgrewriteof),恢复数据,这是一个部分复制或者增量复制的过程

至此,数据同步工作完成。slave具有master端全部数据,包括RDB接收到的全部数据;master保存salve当前同步数据的位置;两者之间完成数据克隆。

 2.2.3 数据同步阶段master说明

  • 如果master数据量巨大,数据同步阶段应该避免高峰期,避免造成master的阻塞,影响业务正常进行;
  • 复制缓冲区大小如果设置不合理,会导致数据溢出,如果进行全量复制周期太长,进行部分数据时发现数据已经丢失,部分复制不能正确进行,必须进行二次全量复制,从而陷入死循环;更改指令:repl-backing-size 1mb
  • master单机内存占用主机内存不宜过大,建议使用50%到70%的内存,留下部分内存执行bgsave指令和创建复制缓冲区;

2.2.4 数据同步阶段slave说明

  • 为了避免slave进行全量复制的时候、部分复制的时候服务器响应阻塞或者数据不同步,建议关闭此期间的对外服务;通过指令:slave-serve-stale-data no
  • 多个slave同时对master请求数据同步,master发送的RDB文件较多,会对带宽进行冲击,如果master带宽不足,会造成master性能下降,需要适量错峰;
  • slave过多的时候也可以考虑树型结构,但是注意层级不能过多,否则一致性会变差,而且分层的同时,如果要求一致性高的,读取顶层;如果相对要求不高的,可以读取下一层级,当谨慎选择;

2.3 命令传播阶段

  • 当master数据库状态被修改后,导致主从服务器数据状态不一致,此时需要让主从数据同步到一致的状态,同步的动作叫命令传播
  • master将接收到的数据变更指令发送给slave,slave接收到指令之后执行命令

2.3.1 命令传播阶段的部分复制

在命令传播阶段,可能会出现短时间断网等抖动,这个时候可能就会有部分复制的过程;

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

  • 服务器的运行ID(runid)
  • 主服务器的复制积压缓冲区
  • 主服务器的复制偏移量

2.3.1.1 服务器的运行ID

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

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

作用:在服务器间传输,识别身份;

实现:run id在服务器启动时自动生成,master在首次连接slave时,会将自己的运行ID发给slave,slave进行保存,可以通过info server指令进行查看;

2.3.1.2 复制缓冲区

概念:是一个先进先出的队列,用于存储服务器执行过的命令,每次传播命令,master都会把传播的命令记录下来,并存储在复制缓冲区

内部工作原理:

 当master接收到一直指令后,会把这个指令放在复制积压缓冲区,当然,这个命令不是直接放进去,而且进行了相应的转换,按照字符来记录,而缓冲区亦做了相应的分割。

 整个复制缓冲区由两个部分组成,一个是偏移量offset(slave通过offset来记录复制到哪里了,这个值slave和master都会记录),一个是字节值。

 作用:用来保存master收到的所有指令,仅仅是影响数据变更的指令,例如set等;

 产生:每个服务器启动的时候,如果开启有AOF或者被连接成为master节点,创建复制缓冲区;

 数据来源:当master接收到客户端的指令时,除了将该指令执行,会将该指令保存到缓冲区中;

2.3.1.3 主从复制偏移量offset

 概念:描述复制缓冲区中指令字节的位置

 分类:master复制偏移量(可能有多个),slave复制偏移量(一个)

 数据来源:master端为记录一次发送一次;slave端为接收一次记录一次;

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

 2.4 再述数据同步加命令传播阶段的工作流程

这个部分我们再详细说一下这个过程:

 

 

  •  当服务器启动的时候,首先master首选得产生自己的复制缓冲区,接下来,slave向master发送指令,第一次,slave并不知道master的runid和偏移量,所以发送psync2 ? -1 ,相当于告诉master有啥数据就全部发送过来;
  • master接收到指令之后,执行bgsave生成RDB文件,记录当前的复制偏移量offset;由于发现slave并不知道自己的runid和偏移量,发送的时候(fullersync)会携带自己的runid和offset,通过socket一起发送给slave
  • slave收到后,这个时候就会保存master的runid和offset信息,根据master给的RDB恢复数据,整个全量复制过程
  • 而到部分复制的过程,slave发送指令psync2 runid offset ,这个时候slave是知道master的runid和offset的;master收到同步指令后,会判断runid是否匹配,判断offset是否在缓冲区,如果有一个不匹配,则执行全量复制的过程;如果OK,则部分复制,并发送continue,意为继续复制;

 2.5 心跳机制

在主从复制过程中,复制数据是一个反复的过程,因为数据可能会一直在变化,master会按照一定的间隙给每一个slave同步数据,这其中就需要心跳机制来保证反复执行;

心跳机制就是进入命令传播阶段,master和slave之间需要进行信息交换,用心跳机制来进行维护,实现双方连接在线;

master的心跳:

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

slave的心跳:

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

注意事项:

  • 当slave多数掉线时,或者延迟较高,master为了保证数据的稳定性,将拒绝所有的连接操作

实现:配置 min-slaves-to-write 2      min-slaves-max-lag 8

           slave数量少于两个,或者所有slave的延迟大于等于8秒时,强制关闭master的写功能,停止数据同步

           slave的数量和延迟就是通过slave向master发送relpcation ack指令做确认来告诉

三、常见问题

3.1. 频繁的全量复制

举例1:如果master重启,runid发生变化,导致所有的slave全量复制?

解决:内部优化方案:

  • master内部创建master_replid变量,使用runid相同策略生成,长度41位,并发送给所有的slave
  • 在master关闭时执行指令shutdown save,进行RDB持久化,将runid和offset保存在RDB文件中;
  • master重启后,加载RDB文件,恢复数据;将保存在RDB文件中的repl-id和repl-offset加载到内存中,可以通过info信息查看

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

举例2:网络环境不好,出现网络中断,slave没法正常提供服务

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

解决:修改缓冲区大小,通过repl-backlog-size

           建议设置:2 * (master到slave重连平均时长) *  (master平均每秒产生写命令数据的总量)

3.2  master CPU 占用过高

现象:master CPU占用过高

原因:

  • slave每一秒发送 REPLCONF ACK命令到master请求数据
  • slave接收到慢查询时,如keys * , hgetall 等,占用大量的CPU性能
  • master每秒轮巡调用复制定时函数replicationCron(),比对slave发现长时间没有响应(slave那边遭受慢查询之类的场景)

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

解决:设置合理的超时时间,确认是否释放slave,断开slave

           设置:repl-timeout 默认60秒,超过该值,释放slave

3.3 slave频繁断开连接

现象:slave 与master断开连接

原因:

  • master发送ping指令频率过低
  • master设置超时时间较短
  • ping指令在网络中存在丢包

解决:提高ping指令的发送频度,通过设置参数repl-ping-slave-period

           一般来说,超时时间repl-time是ping指令频度的5到10倍比较好

3.4 数据不一致

现象:多个slave获取相同数据不同步

原因:网络信息不同步,数据发送有延迟

解决:

  • 优化主从网络环境,通常可以同机房部署
  • 监控主从节点延迟(通过offset判断),如果slave延迟较大,暂时屏蔽程序对该slave的数据访问,注意只能是暂时性策略,参数设置:slave-serve-stale-data yes/no,参数开启后,仅仅只会响应info、slaveof等少数指令,基本对外不能提供服务了,这种设置除非对数据一致性有特别高的要求;

 

这一篇就到到这里,下一篇:redis的哨兵模式。

推荐阅读