redis-复制

一、复制介绍

主从复制,是把一台redis服务器上数据复制到其他服务器的机制,其中前者被称为主节点(master),后者被称为从节点(slave)。

主从复制的主要主要作用:

  1. 数据冗余:数据热备,多机备份。
  2. 故障恢复:当主节点出现问题时,可以让从节点提供服务,是一种功能的冗余。
  3. 负载均衡:可以让主节点写,从节点多,可以把压力分配到多个从节点,从而实现负载均衡。
  4. 高可用基石:主从复制是实现哨兵和集群的基础。

默认情况下,每个redis服务器都是master节点,每一个master可以有多个slave节点,但是一个salve节点只能有一个master节点。

二、复制配置

2.1 建立复制

2.1.1 命令

  1. 在配置文件中加入:slaveof
  2. 在redis-server启动命令后加入 -- slaveof
  3. 直接使用命令(在客户端执行): slaveof

2.1.2 演示

准备节点

默认6380端口作为master节点,再启动一个6380节点作为salve节点。

复制一个配置文件,命名为redis6380.conf

配置新的端口号

两个redis实例已经启动。

执行复制命令

启动两个实例

执行slaveof命令

查看效果

master节点写入,读取

slave节点读取数据

至此,复制搭建成功,数据已经成功从master复制到了slave,并且通过salve读取成功。

2.2 断开复制

3.2.1 直接断开

直接使用slaveof no one命令即可断开和master的复制关系

断开复制关系后的数据

  1. 原有已经复制的数据会保留
  2. master后续写入的数据将不再同步

可以看到原有的数据保留了

断开后在原有master写入

数据将不再同步到6380

3.2.2 切换到其他master

可以通过切换到其他master的方式断开和当前master的绑定。但是和slave no one不同的是,切换新的master后,从原有master复制过来的数据会被清空。

三、拓扑结构

一对一,一对多,树状结构。

四、复制过程

4.1保存主节点

执行slaveof后从节点只是保存了主节点的地址信息变直接返回,复制流程还没有正式开始。

4.2 主从建立socket连接

从节点内部通过每秒运行的定时任务来处理相关逻辑,当定时任务发现存在新的主节点后,会尝试和主节点建立网络连接。

从节点会创建一个socket去连接主节点,后续数据同步都是基于这个socket进行。

如果从节点无法建立连接,定时任务会无限重试到连接成功或者复制被取消为止。

4.3 发送ping命令

连接建立成功后从节点会向主节点发送ping请求进行首次通信,主要有如下目的:

  1. 检测之前建立的socket是否可用。
  2. 检测主节点当前是否可接受处理命令

发送ping命令后如果从节点没有收到pong回复或者超时(比如网络超时,或者主节点阻塞无法处理等),从节点会断开复制,下次定时任务发起后重新连接。

4.4 权限验证

如果主节点设置了requirepass参数,则需要密码验证,从节点必须配置masterauth参数保证与主节点相同的密码才能通过验证,如果验证失败,从节点会断开复制,下次定时任务发起后重新连接。

4.5 数据同步

主从复制连接建立成功后,便开始数据同步,属于数据的初始化,主节点会把持有的所有数据发送给从节点,主题是实现方式是从节点给主节点发送psync命令(2.8之前是sync命令)。这块是耗时最长的步骤,分为全量同步和部分同步。

4.6 命令持续同步

当主节点把当前的数据同步给从节点后,便完成了复制的建立流程,后续主节点会持续的把命令发送给从节点,保证主从一致。

五、数据同步原理

主从建立连接成功后,从节点会向主节点发送psync命令来完成数据同步,同步过程分为:全量复制和部分复制。

  1. 全量复制:一般用于初次复制场景,主节点一次性把全部数据发给从节点,是一个比较重的操作
  2. 部分复制:用于处理在主从复制中因网络闪断等原因造成的数据丢失的场景,当主从再次连接后,如果主节点完整保存了中断期间的数据,主节点会补发丢失的数据给从节点,补发的数据远远小于全量数据,部分复制有效避免了全量复制的过高开销。

5.1 psync命令需要的组件

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

  1. 主从复制偏移量
  2. 主节点复制挤压缓冲区
  3. 主节点运行id

5.1.1 主从复制偏移量

master节点处理完写入命令后,会把命令的字节长度做累加记录。

从节点再接收到主节点发送的命令后,也会累加自身的偏移量。

通过对比master的偏移量和slave的偏移量来看slave和master的数据差异大小。

5.1.2 主节点复制积压缓冲区

复制缓冲区是保存在主节点上的一个固定长度队列,默认大小为1MB,当有slave时候回创建缓冲区,这时主节点响应写命令时,不但会把命令发送给从节点,还会写入复制挤压缓冲区。

挤压缓冲区是一个先进先出的队列,如果超过容量,之前的数据会被覆盖。大小是可以配置的。挤压缓冲区主要为了部分复制做准备。可以通过info replication来查看:

repl_backlog_active:1 //开启复制缓冲区
repl_backlog_size:1048576 //缓冲区最大长度
repl_backlog_first_byte_offset:4505 //起始变异量,计算当前缓冲区可用范围
repl_backlog_histlen:5460 //已保存数据的有效长度

5.1.3 主节点运行id

每个redis节点(主从)启动后都会生成一个40位的16进制的字符串作为运行id,用于唯一识别一个redis节点。从节点会保存主节点的运行id用于识别自己正在复制的是哪一个主节点。redis重启后id会改变。

初次复制时,从节点会保存主节点的runid。

5.2 psync命令

从节点通过给主节点发送psync命令实现部分复制或者全量复制。命令格式为:

psync {runid} {offset}
  1. runid:所辅助主节点的runid,
  2. offset:当前从节点的数据偏移量

第一次复制时没有offset和主节点的runid,会发送psync -1命令

5.3 全量复制

  1. 首次复制发送 psync ? -1
  2. master 继续请求发现是全量复制,恢复fullresync
  3. slave保存主节点响应的runid和 offset
  4. 主节点执行bgsave,并且把从选择开始的命令同时写入一个缓冲区(复制缓冲区)
  5. 主节点执行完bgsave后把最终生成的rdb发给salve。
  6. salve收到主节点发送过来的rdb后开始清空自身数据
  7. salve把主节点的rdb载入自己的rdb,此时salve的数据更新至主节点执行bgsave时候的状态。
  8. 主节点将复制缓冲区的命令发送给salve
  9. slave执行接收到的复制缓冲区的命令,至此salve的数据更新至主节点的最新状态
  10. 如果slave开启了aof,则会立即做bgrewriteaof,确保全量复制后aof持久化文件立即可用。

5.4 部分复制

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

当主从复制的过程中,如果出现网络闪断或者命令丢失等异常情况,从节点会要求主节点补发数据,如果此时主节点的复制积压缓冲区内存中刚好存在这部分数据(就是断网这段时间没有同步到从节点的数据),则直接发给从节点,最终保持了和从节点的一直,也避免了大规模的全量复制。

  1. 如果主从节点之间网络出现中断,如果超过repl-timeout时间,主节点会认为从节点故障并中断复制连接。
  2. 主从断开后,主节点依然在响应命令,这个时候新的命令无法同步到从节点,主从出现了不一致。上面也解释了主节点会默认将命令写入到复制积压缓冲区,默认为1M,超出后会覆盖。
  3. 网络恢复了,从节点再次连接主节点,连接建立成功。
  4. 从节点保存了主节点的runid和自身的复制偏移量(offset),通过psync {runid} {offset}命令和主节点进行交互
  5. 主节点如果发现满足部分复制的条件(后面详细解释这个条件),则返回continue给从节点
  6. 主节点根据偏移量把复制积压缓冲区的数据发给从节点,最终保证主从复制进入正常。

主节点判断判断满足部分复制的条件

  1. runid必须和自身一致
  2. 从节点发过来的偏移量之后的数据都在自身的复制积压缓冲区内,这个很好理解,比如从节点发过来的offset是10(代表10以后的数据都没有同步),但是缓冲区的offset是15(说明15之前的的数据已经不在缓冲区了),这个时候就没办法进行部分复制

如果不满足部分复制条件,则主节点会返回fullsync给从节点,从节点会开启全量复制

由此可见复制积压缓冲区的大小比较重要,如果太小,会被覆盖,最终导致主从网络恢复后无法进行部分复制,这个值得大小应该要基于网络的中断时间,已经主节点的qps和命令的大小来进行计算,然后进行合理的设置。

六、主从心跳

6.1 流程

主从心跳检测示意图

  1. master会周期性的ping slave,周期时间通过repl-ping-replica-period参数来控制,默认是10秒

  2. slave每隔1秒回向master发送replconf ack {offset}命令:

    • 实时监测主从节点的网络状态

    • 上报自身的数据复制偏移量,如果主节点发现从节点有数据缺失,主节点会从自身的复制积压缓冲区中拉取数据发给从节点

    • 实现从节点的数量和延迟性功能,通过min-replicas-to-write(最小可用的从节点个数)和min-replicas-max-lag(允许的最小延迟秒,一般为0,或者1)参数定义。

      • 如果master开启了这两个参数,那么如果可用的从节点小于min-replicas-to-write或者延迟大于min-replicas-max-lag,master会拒绝数据写入。示意图如下。

6.2 repl -timeout参数

redis.conf有个repl-timeout参数:

  1. slave角度,如果在repl-timeout时间内没有收到传输的rdb snapshot数据,

  2. slave角度,如果在repl-timeout没有收到master发送的数据包或者ping。

  3. master角度,如果在repl-timeout时间没有收到REPCONF ACK确认信息。

当redis检测到repl-timeout超时(默认值60s),将会关闭主从之间的连接,redis slave会重新建立主从连接的请求。这个值一定要大于repl-ping-replica-period参数

为了降低主从延迟,一般建议把redis的主从节点部署在相同的机房。

七、全量复制场景

全量复制非常重,应该尽量避免,下面是一些会导致全量复制的操作。

  1. 第一次建立复制,无法避免,建议低峰时候进行
  2. runid不匹配,从节点会保存主节点的runid,如果主节点重启,则主节点的runid会改变,发现和从节点保存的runid不一致时,会进行全量复制,应该避免重启,比如可以采用debug reload命令,或者采用故障转移功能,当主节点发生故障后,可以将从节点提升为主节点,或者采用哨兵或者集群方案
  3. 复制积压缓冲区不足(repl-backlog-size),这个缓冲区默认大小为1M,当超过1m后覆盖,主从中断再次连接后如果从节点的offset在复制积压缓冲区找不到,则会导致全量复制,这个缓冲区的大小要基于网络状况,命令大小,以及qps进行计算配置。

七、一些配置和命令

  1. salve-read-only=yes。 从节点只读,如果从节点修改,会造成主从数据不一致
  2. repl-disable-tcp-nodelay 是否关闭tcp_nodelay,默认为no,建议配置为yes。这个是服务器tcp的一个功能,tcp nagle算法
  3. debug reload,不会导致runid改变,但是会情况内存数据,再次从rdb加载。
  4. 。。。
posted @ 2020-12-27 16:55  xuan_wu  阅读(258)  评论(0编辑  收藏  举报