redis-复制

1、复制介绍

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

主从复制的主要主要做用:node

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

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

2、复制配置

2.1 创建复制

2.1.1 命令

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

2.1.2 演示

准备节点算法

默认6380端口做为master节点,再启动一个6380节点做为salve节点。服务器

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

配置新的端口号负载均衡

两个redis实例已经启动。socket

执行复制命令tcp

启动两个实例优化

执行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复制过来的数据会被清空。

3、拓扑结构

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

4、复制过程

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 命令持续同步

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

5、数据同步原理

主从创建链接成功后,从节点会向主节点发送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 {runid} {offset}
  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、主从心跳

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的主从节点部署在相同的机房。

7、全量复制场景

全量复制很是重,应该尽可能避免,下面是一些会致使全量复制的操做。

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

7、一些配置和命令

  1. salve-read-only=yes。 从节点只读,若是从节点修改,会形成主从数据不一致
  2. repl-disable-tcp-nodelay 是否关闭tcp_nodelay,默认为no,建议配置为yes。这个是服务器tcp的一个功能,tcp nagle算法
  3. debug reload,不会致使runid改变,可是会状况内存数据,再次从rdb加载。
  4. 。。。
相关文章
相关标签/搜索